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::ec::compressed_public_key_size_bytes;
10use crate::ec::encoding::parse_ec_public_key;
11use crate::ec::encoding::sec1::marshal_sec1_public_point;
12use crate::encoding::{
13 AsBigEndian, AsDer, EcPublicKeyCompressedBin, EcPublicKeyUncompressedBin, PublicKeyX509Der,
14};
15use crate::error::Unspecified;
16use crate::evp_pkey::No_EVP_PKEY_CTX_consumer;
17use crate::ptr::{DetachableLcPtr, LcPtr};
18use crate::signature::VerificationAlgorithm;
19use crate::{digest, sealed};
20use core::fmt;
21use core::fmt::{Debug, Formatter};
22use std::mem::MaybeUninit;
23use std::ops::Deref;
24use std::ptr::null_mut;
25#[cfg(feature = "ring-sig-verify")]
26use untrusted::Input;
27
28#[derive(Debug, Eq, PartialEq)]
30pub struct EcdsaVerificationAlgorithm {
31 pub(crate) id: &'static AlgorithmID,
32 pub(crate) digest: &'static digest::Algorithm,
33 pub(crate) sig_format: EcdsaSignatureFormat,
34}
35
36#[derive(Debug, Eq, PartialEq)]
38pub struct EcdsaSigningAlgorithm(pub(crate) &'static EcdsaVerificationAlgorithm);
39
40impl Deref for EcdsaSigningAlgorithm {
41 type Target = EcdsaVerificationAlgorithm;
42 #[inline]
43 fn deref(&self) -> &Self::Target {
44 self.0
45 }
46}
47
48impl sealed::Sealed for EcdsaVerificationAlgorithm {}
49impl sealed::Sealed for EcdsaSigningAlgorithm {}
50
51#[derive(Debug, Eq, PartialEq)]
52pub(crate) enum EcdsaSignatureFormat {
53 ASN1,
54 Fixed,
55}
56
57#[derive(Debug, Eq, PartialEq)]
58#[allow(non_camel_case_types)]
59pub(crate) enum AlgorithmID {
60 ECDSA_P256,
61 ECDSA_P384,
62 ECDSA_P521,
63 ECDSA_P256K1,
64}
65
66impl AlgorithmID {
67 #[inline]
68 pub(crate) fn nid(&'static self) -> i32 {
69 match self {
70 AlgorithmID::ECDSA_P256 => NID_X9_62_prime256v1,
71 AlgorithmID::ECDSA_P384 => NID_secp384r1,
72 AlgorithmID::ECDSA_P521 => NID_secp521r1,
73 AlgorithmID::ECDSA_P256K1 => NID_secp256k1,
74 }
75 }
76 pub(crate) fn private_key_size(&self) -> usize {
77 match self {
78 AlgorithmID::ECDSA_P256 | AlgorithmID::ECDSA_P256K1 => 32,
79 AlgorithmID::ECDSA_P384 => 48,
80 AlgorithmID::ECDSA_P521 => 66,
81 }
82 }
83 #[inline]
85 #[allow(dead_code)]
86 const fn compressed_pub_key_len(&self) -> usize {
87 match self {
88 AlgorithmID::ECDSA_P256 | AlgorithmID::ECDSA_P256K1 => {
89 compressed_public_key_size_bytes(256)
90 }
91 AlgorithmID::ECDSA_P384 => compressed_public_key_size_bytes(384),
92 AlgorithmID::ECDSA_P521 => compressed_public_key_size_bytes(521),
93 }
94 }
95}
96
97#[derive(Clone)]
99pub struct PublicKey {
100 #[allow(dead_code)]
101 algorithm: &'static EcdsaSigningAlgorithm,
102 evp_pkey: LcPtr<EVP_PKEY>,
103 octets: Box<[u8]>,
104}
105
106pub(crate) fn public_key_from_evp_pkey(
107 evp_pkey: &LcPtr<EVP_PKEY>,
108 algorithm: &'static EcdsaSigningAlgorithm,
109) -> Result<PublicKey, Unspecified> {
110 let pub_key_bytes = marshal_sec1_public_point(evp_pkey, false)?;
111
112 Ok(PublicKey {
113 evp_pkey: evp_pkey.clone(),
114 algorithm,
115 octets: pub_key_bytes.into_boxed_slice(),
116 })
117}
118
119impl AsDer<PublicKeyX509Der<'static>> for PublicKey {
120 fn as_der(&self) -> Result<PublicKeyX509Der<'static>, Unspecified> {
124 let der = self.evp_pkey.marshal_rfc5280_public_key()?;
125 Ok(PublicKeyX509Der::new(der))
126 }
127}
128
129impl AsBigEndian<EcPublicKeyCompressedBin<'static>> for PublicKey {
130 fn as_be_bytes(&self) -> Result<EcPublicKeyCompressedBin<'static>, crate::error::Unspecified> {
134 let pub_point = marshal_sec1_public_point(&self.evp_pkey, true)?;
135 Ok(EcPublicKeyCompressedBin::new(pub_point))
136 }
137}
138
139impl AsBigEndian<EcPublicKeyUncompressedBin<'static>> for PublicKey {
140 fn as_be_bytes(
144 &self,
145 ) -> Result<EcPublicKeyUncompressedBin<'static>, crate::error::Unspecified> {
146 let mut uncompressed_bytes = vec![0u8; self.octets.len()];
147 uncompressed_bytes.copy_from_slice(&self.octets);
148 Ok(EcPublicKeyUncompressedBin::new(uncompressed_bytes))
149 }
150}
151
152impl Debug for PublicKey {
153 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
154 f.write_str(&format!(
155 "EcdsaPublicKey(\"{}\")",
156 crate::hex::encode(self.octets.as_ref())
157 ))
158 }
159}
160
161impl AsRef<[u8]> for PublicKey {
162 #[inline]
163 fn as_ref(&self) -> &[u8] {
167 self.octets.as_ref()
168 }
169}
170
171unsafe impl Send for PublicKey {}
172unsafe impl Sync for PublicKey {}
173
174impl VerificationAlgorithm for EcdsaVerificationAlgorithm {
175 #[inline]
176 #[cfg(feature = "ring-sig-verify")]
177 fn verify(
178 &self,
179 public_key: Input<'_>,
180 msg: Input<'_>,
181 signature: Input<'_>,
182 ) -> Result<(), Unspecified> {
183 self.verify_sig(
184 public_key.as_slice_less_safe(),
185 msg.as_slice_less_safe(),
186 signature.as_slice_less_safe(),
187 )
188 }
189
190 fn verify_sig(
191 &self,
192 public_key: &[u8],
193 msg: &[u8],
194 signature: &[u8],
195 ) -> Result<(), Unspecified> {
196 match self.sig_format {
197 EcdsaSignatureFormat::ASN1 => {
198 verify_asn1_signature(self.id, self.digest, public_key, msg, signature)
199 }
200 EcdsaSignatureFormat::Fixed => {
201 verify_fixed_signature(self.id, self.digest, public_key, msg, signature)
202 }
203 }
204 }
205}
206
207fn verify_fixed_signature(
208 alg: &'static AlgorithmID,
209 digest: &'static digest::Algorithm,
210 public_key: &[u8],
211 msg: &[u8],
212 signature: &[u8],
213) -> Result<(), Unspecified> {
214 let mut out_bytes = null_mut::<u8>();
215 let mut out_bytes_len = MaybeUninit::<usize>::uninit();
216 let sig = unsafe { ecdsa_sig_from_fixed(alg, signature)? };
217 if 1 != unsafe {
218 ECDSA_SIG_to_bytes(&mut out_bytes, out_bytes_len.as_mut_ptr(), *sig.as_const())
219 } {
220 return Err(Unspecified);
221 }
222 let out_bytes = LcPtr::new(out_bytes)?;
223 let signature = unsafe { out_bytes.as_slice(out_bytes_len.assume_init()) };
224 verify_asn1_signature(alg, digest, public_key, msg, signature)
225}
226
227fn verify_asn1_signature(
228 alg: &'static AlgorithmID,
229 digest: &'static digest::Algorithm,
230 public_key: &[u8],
231 msg: &[u8],
232 signature: &[u8],
233) -> Result<(), Unspecified> {
234 let evp_pkey = parse_ec_public_key(public_key, alg.nid())?;
235 evp_pkey.verify(msg, Some(digest), No_EVP_PKEY_CTX_consumer, signature)
236}
237
238#[inline]
239unsafe fn ecdsa_sig_from_fixed(
240 alg_id: &'static AlgorithmID,
241 signature: &[u8],
242) -> Result<LcPtr<ECDSA_SIG>, ()> {
243 let num_size_bytes = alg_id.private_key_size();
244 if signature.len() != 2 * num_size_bytes {
245 return Err(());
246 }
247 let mut r_bn = DetachableLcPtr::<BIGNUM>::try_from(&signature[..num_size_bytes])?;
248 let mut s_bn = DetachableLcPtr::<BIGNUM>::try_from(&signature[num_size_bytes..])?;
249
250 let mut ecdsa_sig = LcPtr::new(ECDSA_SIG_new())?;
251
252 if 1 != ECDSA_SIG_set0(*ecdsa_sig.as_mut(), *r_bn.as_mut(), *s_bn.as_mut()) {
253 return Err(());
254 }
255 r_bn.detach();
256 s_bn.detach();
257
258 Ok(ecdsa_sig)
259}