aws_db_esdk/
ecdsa.rs

1// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
2// SPDX-License-Identifier: Apache-2.0
3
4#![deny(warnings, unconditional_panic)]
5#![deny(nonstandard_style)]
6#![deny(clippy::all)]
7
8#[allow(non_snake_case)]
9pub mod Signature {
10    pub mod ECDSA {
11        use crate::software::amazon::cryptography::primitives::internaldafny::types::ECDSASignatureAlgorithm;
12        use crate::software::amazon::cryptography::primitives::internaldafny::types::Error as DafnyError;
13        use crate::*;
14        use aws_lc_rs::encoding::AsDer;
15        use aws_lc_rs::rand::SystemRandom;
16        use aws_lc_rs::signature::EcdsaKeyPair;
17        use aws_lc_rs::signature::EcdsaSigningAlgorithm;
18        use aws_lc_rs::signature::EcdsaVerificationAlgorithm;
19        use aws_lc_rs::signature::KeyPair;
20        use aws_lc_rs::signature::UnparsedPublicKey;
21        use dafny_runtime::Rc;
22
23        fn error(s: &str) -> Rc<DafnyError> {
24            Rc::new(DafnyError::AwsCryptographicPrimitivesError {
25                message:
26                    dafny_runtime::dafny_runtime_conversions::unicode_chars_false::string_to_dafny_string(s),
27            })
28        }
29
30        fn get_alg(x: &ECDSASignatureAlgorithm) -> &'static EcdsaSigningAlgorithm {
31            match x {
32                ECDSASignatureAlgorithm::ECDSA_P256 {} => {
33                    // &aws_lc_rs::signature::ECDSA_P256_SHA256_FIXED_SIGNING
34                    &aws_lc_rs::signature::ECDSA_P256_SHA256_ASN1_SIGNING
35                }
36                ECDSASignatureAlgorithm::ECDSA_P384 {} => {
37                    // &aws_lc_rs::signature::ECDSA_P384_SHA384_FIXED_SIGNING
38                    &aws_lc_rs::signature::ECDSA_P384_SHA384_ASN1_SIGNING
39                }
40            }
41        }
42
43        fn get_ver_alg(x: &ECDSASignatureAlgorithm) -> &'static EcdsaVerificationAlgorithm {
44            match x {
45                ECDSASignatureAlgorithm::ECDSA_P256 {} => {
46                    // &aws_lc_rs::signature::ECDSA_P256_SHA256_FIXED
47                    &aws_lc_rs::signature::ECDSA_P256_SHA256_ASN1
48                }
49                ECDSASignatureAlgorithm::ECDSA_P384 {} => {
50                    // &aws_lc_rs::signature::ECDSA_P384_SHA384_FIXED
51                    &aws_lc_rs::signature::ECDSA_P384_SHA384_ASN1
52                }
53            }
54        }
55
56        fn get_nid(x: &ECDSASignatureAlgorithm) -> i32 {
57            match x {
58                ECDSASignatureAlgorithm::ECDSA_P256 {} => aws_lc_sys_impl::NID_X9_62_prime256v1,
59                ECDSASignatureAlgorithm::ECDSA_P384 {} => aws_lc_sys_impl::NID_secp384r1,
60            }
61        }
62
63        const ELEM_MAX_BITS: usize = 521;
64        const ELEM_MAX_BYTES: usize = ELEM_MAX_BITS.div_ceil(8);
65        const PUBLIC_KEY_MAX_LEN: usize = 1 + (2 * ELEM_MAX_BYTES);
66
67        pub(crate) fn sec1_compress(
68            data: &[u8],
69            alg: &ECDSASignatureAlgorithm,
70        ) -> Result<Vec<u8>, String> {
71            sec1_convert(
72                data,
73                get_nid(alg),
74                aws_lc_sys_impl::point_conversion_form_t::POINT_CONVERSION_COMPRESSED,
75            )
76        }
77
78        pub(crate) fn sec1_convert(
79            data: &[u8],
80            nid: i32,
81            form: aws_lc_sys_impl::point_conversion_form_t,
82        ) -> Result<Vec<u8>, String> {
83            use aws_lc_sys_impl::EC_GROUP_new_by_curve_name;
84            use aws_lc_sys_impl::EC_POINT_free;
85            use aws_lc_sys_impl::EC_POINT_new;
86            use aws_lc_sys_impl::EC_POINT_oct2point;
87            use aws_lc_sys_impl::EC_POINT_point2oct;
88            use std::ptr::null_mut;
89
90            // no need to free ec_group
91            let ec_group = unsafe { EC_GROUP_new_by_curve_name(nid) };
92            if ec_group.is_null() {
93                return Err("EC_GROUP_new_by_curve_name returned failure.".to_string());
94            }
95
96            let ec_point = unsafe { EC_POINT_new(ec_group) };
97            if ec_point.is_null() {
98                return Err("EC_POINT_new returned failure.".to_string());
99            }
100            let mut out_buf = [0u8; PUBLIC_KEY_MAX_LEN];
101
102            let ret = unsafe {
103                EC_POINT_oct2point(ec_group, ec_point, data.as_ptr(), data.len(), null_mut())
104            };
105            if ret == 0 {
106                return Err("EC_POINT_oct2point returned failure.".to_string());
107            }
108            let new_size: usize = unsafe {
109                EC_POINT_point2oct(
110                    ec_group,
111                    ec_point,
112                    form,
113                    out_buf.as_mut_ptr(),
114                    PUBLIC_KEY_MAX_LEN,
115                    null_mut(),
116                )
117            };
118            unsafe { EC_POINT_free(ec_point) };
119            Ok(out_buf[..new_size].to_vec())
120        }
121
122        fn ecdsa_key_gen(alg: &ECDSASignatureAlgorithm) -> Result<(Vec<u8>, Vec<u8>), String> {
123            let pair = EcdsaKeyPair::generate(get_alg(alg)).map_err(|e| format!("{e:?}"))?;
124
125            let public_key: Vec<u8> = sec1_compress(pair.public_key().as_ref(), alg)?;
126            let private_key: Vec<u8> = pair.private_key().as_der().unwrap().as_ref().to_vec();
127            Ok((public_key, private_key))
128        }
129
130        pub fn ExternKeyGen(
131            alg: &Rc<ECDSASignatureAlgorithm>,
132        ) -> Rc<_Wrappers_Compile::Result<Rc<Signature::SignatureKeyPair>, Rc<DafnyError>>>
133        {
134            match ecdsa_key_gen(alg) {
135                Ok(x) => Rc::new(_Wrappers_Compile::Result::Success {
136                    value: Rc::new(Signature::SignatureKeyPair::SignatureKeyPair {
137                        verificationKey: dafny_runtime::Sequence::from_array_owned(x.0),
138                        signingKey: dafny_runtime::Sequence::from_array_owned(x.1),
139                    }),
140                }),
141                Err(e) => {
142                    let msg = format!("ECDSA Key Gen : {e}");
143                    Rc::new(_Wrappers_Compile::Result::Failure { error: error(&msg) })
144                }
145            }
146        }
147
148        fn ecdsa_sign_inner(
149            alg: &ECDSASignatureAlgorithm,
150            key: &[u8],
151            msg: &[u8],
152        ) -> Result<Vec<u8>, String> {
153            let private_key = EcdsaKeyPair::from_private_key_der(get_alg(alg), key)
154                .map_err(|e| format!("{e:?}"))?;
155            let rng = SystemRandom::new();
156            let sig = private_key.sign(&rng, msg).map_err(|e| format!("{e:?}"))?;
157            Ok(sig.as_ref().to_vec())
158        }
159        fn ecdsa_sign(
160            alg: &ECDSASignatureAlgorithm,
161            key: &[u8],
162            msg: &[u8],
163        ) -> Result<Vec<u8>, String> {
164            // This loop can in theory run forever, but the chances of that are negligible.
165            // We may want to consider failing, after some number of loops, if we can do so in a way consistent with other ESDKs.
166            loop {
167                let result = ecdsa_sign_inner(alg, key, msg)?;
168                if (get_alg(alg) == &aws_lc_rs::signature::ECDSA_P384_SHA384_ASN1_SIGNING
169                    && result.len() == 103)
170                    || (get_alg(alg) == &aws_lc_rs::signature::ECDSA_P256_SHA256_ASN1_SIGNING
171                        && result.len() == 71)
172                {
173                    return Ok(result);
174                }
175            }
176        }
177
178        pub fn Sign(
179            alg: &Rc<ECDSASignatureAlgorithm>,
180            key: &::dafny_runtime::Sequence<u8>,
181            msg: &::dafny_runtime::Sequence<u8>,
182        ) -> Rc<_Wrappers_Compile::Result<::dafny_runtime::Sequence<u8>, Rc<DafnyError>>> {
183            let key = &key.to_array();
184            let msg = &msg.to_array();
185            match ecdsa_sign(alg, key, msg) {
186                Ok(x) => Rc::new(_Wrappers_Compile::Result::Success {
187                    value: dafny_runtime::Sequence::from_array_owned(x),
188                }),
189                Err(e) => {
190                    let msg = format!("ECDSA Sign : {e}");
191                    Rc::new(_Wrappers_Compile::Result::Failure { error: error(&msg) })
192                }
193            }
194        }
195
196        fn ecdsa_verify(
197            alg: &ECDSASignatureAlgorithm,
198            key: &[u8],
199            msg: &[u8],
200            sig: &[u8],
201        ) -> Result<bool, String> {
202            let public_key = UnparsedPublicKey::new(get_ver_alg(alg), key);
203            match public_key.verify(msg, sig) {
204                Ok(_) => Ok(true),
205                Err(_) => Ok(false),
206            }
207        }
208
209        pub fn Verify(
210            alg: &Rc<ECDSASignatureAlgorithm>,
211            key: &::dafny_runtime::Sequence<u8>,
212            msg: &::dafny_runtime::Sequence<u8>,
213            sig: &::dafny_runtime::Sequence<u8>,
214        ) -> Rc<_Wrappers_Compile::Result<bool, Rc<DafnyError>>> {
215            let key = &key.to_array();
216            let msg = &msg.to_array();
217            let sig = &sig.to_array();
218            match ecdsa_verify(alg, key, msg, sig) {
219                Ok(x) => Rc::new(_Wrappers_Compile::Result::Success { value: x }),
220                Err(e) => {
221                    let msg = format!("ECDSA Verify : {e}");
222                    Rc::new(_Wrappers_Compile::Result::Failure { error: error(&msg) })
223                }
224            }
225        }
226        #[cfg(test)]
227        mod tests {
228            use super::*;
229            use dafny_runtime::Rc;
230
231            #[test]
232            fn test_generate() {
233                let alg = Rc::new(ECDSASignatureAlgorithm::ECDSA_P384 {});
234                let key_pair = match &*ExternKeyGen(&alg) {
235                    _Wrappers_Compile::Result::Success { value } => value.clone(),
236                    _Wrappers_Compile::Result::Failure { error } => {
237                        panic!("ExternKeyGen Failed : {error:?}");
238                    }
239                };
240
241                let (s_key, v_key) = match &*key_pair {
242                    Signature::SignatureKeyPair::SignatureKeyPair {
243                        signingKey,
244                        verificationKey,
245                    } => (signingKey, verificationKey),
246                };
247
248                let message: ::dafny_runtime::Sequence<u8> =
249                    dafny_runtime::Sequence::from_array_owned(vec![1u8, 2, 3, 4, 5]);
250
251                let sig = match &*Sign(&alg, s_key, &message) {
252                    _Wrappers_Compile::Result::Success { value } => value.clone(),
253                    _Wrappers_Compile::Result::Failure { error } => {
254                        panic!("Sign Failed : {error:?}");
255                    }
256                };
257
258                let ver: bool = match &*Verify(&alg, v_key, &message, &sig) {
259                    _Wrappers_Compile::Result::Success { value } => *value,
260                    _Wrappers_Compile::Result::Failure { error } => {
261                        panic!("Verify Failed : {error:?}");
262                    }
263                };
264                assert!(ver);
265
266                let mut sig_vec: Vec<u8> = sig.iter().collect();
267                sig_vec[0] = 42;
268                let sig2: ::dafny_runtime::Sequence<u8> = sig_vec.iter().cloned().collect();
269                assert!(sig != sig2);
270                let ver2: bool = match &*Verify(&alg, v_key, &message, &sig2) {
271                    _Wrappers_Compile::Result::Success { value } => *value,
272                    _Wrappers_Compile::Result::Failure { error } => {
273                        panic!("Verify Failed : {error:?}");
274                    }
275                };
276                assert!(!ver2);
277            }
278        }
279    }
280}