/rust/registry/src/index.crates.io-1949cf8c6b5b557f/aws-lc-rs-1.16.2/src/ed25519.rs
Line | Count | Source |
1 | | // Copyright 2015-2016 Brian Smith. |
2 | | // SPDX-License-Identifier: ISC |
3 | | // Modifications copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. |
4 | | // SPDX-License-Identifier: Apache-2.0 OR ISC |
5 | | |
6 | | use core::fmt; |
7 | | use core::fmt::{Debug, Formatter}; |
8 | | use std::marker::PhantomData; |
9 | | |
10 | | #[cfg(feature = "ring-sig-verify")] |
11 | | use untrusted::Input; |
12 | | |
13 | | use crate::aws_lc::{EVP_PKEY, EVP_PKEY_ED25519}; |
14 | | |
15 | | use crate::buffer::Buffer; |
16 | | use crate::digest::Digest; |
17 | | use crate::encoding::{ |
18 | | AsBigEndian, AsDer, Curve25519SeedBin, Pkcs8V1Der, Pkcs8V2Der, PublicKeyX509Der, |
19 | | }; |
20 | | use crate::error::{KeyRejected, Unspecified}; |
21 | | use crate::evp_pkey::No_EVP_PKEY_CTX_consumer; |
22 | | use crate::pkcs8::{Document, Version}; |
23 | | use crate::ptr::LcPtr; |
24 | | use crate::rand::SecureRandom; |
25 | | use crate::signature::{ |
26 | | KeyPair, ParsedPublicKey, ParsedVerificationAlgorithm, Signature, VerificationAlgorithm, |
27 | | }; |
28 | | use crate::{constant_time, digest, hex, sealed}; |
29 | | |
30 | | /// The length of an Ed25519 public key. |
31 | | pub const ED25519_PUBLIC_KEY_LEN: usize = crate::aws_lc::ED25519_PUBLIC_KEY_LEN as usize; |
32 | | const ED25519_SIGNATURE_LEN: usize = crate::aws_lc::ED25519_SIGNATURE_LEN as usize; |
33 | | const ED25519_SEED_LEN: usize = 32; |
34 | | |
35 | | /// Parameters for `EdDSA` signing and verification. |
36 | | #[derive(Debug)] |
37 | | pub struct EdDSAParameters; |
38 | | |
39 | | impl sealed::Sealed for EdDSAParameters {} |
40 | | |
41 | | impl ParsedVerificationAlgorithm for EdDSAParameters { |
42 | 0 | fn parsed_verify_sig( |
43 | 0 | &self, |
44 | 0 | public_key: &ParsedPublicKey, |
45 | 0 | msg: &[u8], |
46 | 0 | signature: &[u8], |
47 | 0 | ) -> Result<(), Unspecified> { |
48 | 0 | public_key |
49 | 0 | .key() |
50 | 0 | .verify(msg, None, No_EVP_PKEY_CTX_consumer, signature) |
51 | 0 | } |
52 | | |
53 | 0 | fn parsed_verify_digest_sig( |
54 | 0 | &self, |
55 | 0 | _public_key: &ParsedPublicKey, |
56 | 0 | _digest: &Digest, |
57 | 0 | _signature: &[u8], |
58 | 0 | ) -> Result<(), Unspecified> { |
59 | 0 | Err(Unspecified) |
60 | 0 | } |
61 | | } |
62 | | |
63 | | impl VerificationAlgorithm for EdDSAParameters { |
64 | | #[inline] |
65 | | #[cfg(feature = "ring-sig-verify")] |
66 | | fn verify( |
67 | | &self, |
68 | | public_key: Input<'_>, |
69 | | msg: Input<'_>, |
70 | | signature: Input<'_>, |
71 | | ) -> Result<(), Unspecified> { |
72 | | self.verify_sig( |
73 | | public_key.as_slice_less_safe(), |
74 | | msg.as_slice_less_safe(), |
75 | | signature.as_slice_less_safe(), |
76 | | ) |
77 | | } |
78 | | |
79 | | /// Verify `signature` for `msg` using `public_key`. |
80 | | /// |
81 | | /// # Errors |
82 | | /// Returns `Unspecified` if the `msg` cannot be verified using `public_key`. |
83 | 0 | fn verify_sig( |
84 | 0 | &self, |
85 | 0 | public_key: &[u8], |
86 | 0 | msg: &[u8], |
87 | 0 | signature: &[u8], |
88 | 0 | ) -> Result<(), Unspecified> { |
89 | 0 | let evp_pkey = parse_ed25519_public_key(public_key)?; |
90 | 0 | evp_pkey.verify(msg, None, No_EVP_PKEY_CTX_consumer, signature) |
91 | 0 | } |
92 | | |
93 | | /// DO NOT USE. This function is required by `VerificationAlgorithm` but cannot be used w/ Ed25519. |
94 | | /// |
95 | | /// # Errors |
96 | | /// Always returns `Unspecified`. |
97 | 0 | fn verify_digest_sig( |
98 | 0 | &self, |
99 | 0 | _public_key: &[u8], |
100 | 0 | _digest: &digest::Digest, |
101 | 0 | _signature: &[u8], |
102 | 0 | ) -> Result<(), Unspecified> { |
103 | 0 | Err(Unspecified) |
104 | 0 | } |
105 | | } |
106 | | |
107 | 0 | pub(crate) fn parse_ed25519_public_key(key_bytes: &[u8]) -> Result<LcPtr<EVP_PKEY>, KeyRejected> { |
108 | | // If the length of key bytes matches the raw public key size then it has to be that |
109 | 0 | if key_bytes.len() == ED25519_PUBLIC_KEY_LEN { |
110 | 0 | LcPtr::<EVP_PKEY>::parse_raw_public_key(key_bytes, EVP_PKEY_ED25519) |
111 | | } else { |
112 | | // Otherwise we support X.509 SubjectPublicKeyInfo formatted keys which are inherently larger |
113 | 0 | LcPtr::<EVP_PKEY>::parse_rfc5280_public_key(key_bytes, EVP_PKEY_ED25519) |
114 | | } |
115 | 0 | } |
116 | | |
117 | | /// An Ed25519 key pair, for signing. |
118 | | #[allow(clippy::module_name_repetitions)] |
119 | | pub struct Ed25519KeyPair { |
120 | | evp_pkey: LcPtr<EVP_PKEY>, |
121 | | public_key: PublicKey, |
122 | | } |
123 | | |
124 | | impl Debug for Ed25519KeyPair { |
125 | 0 | fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> { |
126 | 0 | f.write_str(&format!( |
127 | 0 | "Ed25519KeyPair {{ public_key: PublicKey(\"{}\") }}", |
128 | 0 | hex::encode(&self.public_key) |
129 | 0 | )) |
130 | 0 | } |
131 | | } |
132 | | |
133 | | #[derive(Clone)] |
134 | | #[allow(clippy::module_name_repetitions)] |
135 | | /// The seed value for the `EdDSA` signature scheme using Curve25519 |
136 | | pub struct Seed<'a> { |
137 | | bytes: Box<[u8]>, |
138 | | phantom: PhantomData<&'a [u8]>, |
139 | | } |
140 | | |
141 | | impl AsBigEndian<Curve25519SeedBin<'static>> for Seed<'_> { |
142 | | /// Exposes the seed encoded as a big-endian fixed-length integer. |
143 | | /// |
144 | | /// For most use-cases, `EcdsaKeyPair::to_pkcs8()` should be preferred. |
145 | | /// |
146 | | /// # Errors |
147 | | /// `error::Unspecified` if serialization failed. |
148 | 0 | fn as_be_bytes(&self) -> Result<Curve25519SeedBin<'static>, Unspecified> { |
149 | 0 | Ok(Curve25519SeedBin::new(self.bytes.to_vec())) |
150 | 0 | } |
151 | | } |
152 | | |
153 | | impl Debug for Seed<'_> { |
154 | 0 | fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { |
155 | 0 | f.write_str("Ed25519Seed()") |
156 | 0 | } |
157 | | } |
158 | | |
159 | | #[derive(Clone)] |
160 | | #[allow(clippy::module_name_repetitions)] |
161 | | /// Ed25519 Public Key |
162 | | pub struct PublicKey { |
163 | | evp_pkey: LcPtr<EVP_PKEY>, |
164 | | public_key_bytes: [u8; ED25519_PUBLIC_KEY_LEN], |
165 | | } |
166 | | |
167 | | impl AsRef<[u8]> for PublicKey { |
168 | | #[inline] |
169 | | /// Returns the "raw" bytes of the ED25519 public key |
170 | 0 | fn as_ref(&self) -> &[u8] { |
171 | 0 | &self.public_key_bytes |
172 | 0 | } Unexecuted instantiation: <aws_lc_rs::ed25519::PublicKey as core::convert::AsRef<[u8]>>::as_ref Unexecuted instantiation: <aws_lc_rs::ed25519::PublicKey as core::convert::AsRef<[u8]>>::as_ref |
173 | | } |
174 | | |
175 | | impl Debug for PublicKey { |
176 | 0 | fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { |
177 | 0 | f.write_str(&format!( |
178 | 0 | "PublicKey(\"{}\")", |
179 | 0 | hex::encode(self.public_key_bytes) |
180 | 0 | )) |
181 | 0 | } |
182 | | } |
183 | | |
184 | | unsafe impl Send for PublicKey {} |
185 | | unsafe impl Sync for PublicKey {} |
186 | | |
187 | | impl AsDer<PublicKeyX509Der<'static>> for PublicKey { |
188 | | /// Provides the public key as a DER-encoded (X.509) `SubjectPublicKeyInfo` structure. |
189 | | /// # Errors |
190 | | /// Returns an error if the public key fails to marshal to X.509. |
191 | 0 | fn as_der(&self) -> Result<PublicKeyX509Der<'static>, crate::error::Unspecified> { |
192 | | // Initial size of 44 based on: |
193 | | // 0:d=0 hl=2 l= 42 cons: SEQUENCE |
194 | | // 2:d=1 hl=2 l= 5 cons: SEQUENCE |
195 | | // 4:d=2 hl=2 l= 3 prim: OBJECT :ED25519 |
196 | | // 9:d=1 hl=2 l= 33 prim: BIT STRING |
197 | 0 | let der = self.evp_pkey.as_const().marshal_rfc5280_public_key()?; |
198 | 0 | Ok(PublicKeyX509Der::from(Buffer::new(der))) |
199 | 0 | } |
200 | | } |
201 | | |
202 | | impl KeyPair for Ed25519KeyPair { |
203 | | type PublicKey = PublicKey; |
204 | | #[inline] |
205 | 0 | fn public_key(&self) -> &Self::PublicKey { |
206 | 0 | &self.public_key |
207 | 0 | } Unexecuted instantiation: <aws_lc_rs::ed25519::Ed25519KeyPair as aws_lc_rs::signature::KeyPair>::public_key Unexecuted instantiation: <aws_lc_rs::ed25519::Ed25519KeyPair as aws_lc_rs::signature::KeyPair>::public_key |
208 | | } |
209 | | |
210 | | unsafe impl Send for Ed25519KeyPair {} |
211 | | unsafe impl Sync for Ed25519KeyPair {} |
212 | | |
213 | 0 | pub(crate) fn generate_key() -> Result<LcPtr<EVP_PKEY>, Unspecified> { |
214 | 0 | LcPtr::<EVP_PKEY>::generate(EVP_PKEY_ED25519, No_EVP_PKEY_CTX_consumer) |
215 | 0 | } |
216 | | |
217 | | impl Ed25519KeyPair { |
218 | | /// Generates a new key pair and returns the key pair. |
219 | | /// |
220 | | /// # Errors |
221 | | /// `error::Unspecified` if key generation fails. |
222 | 0 | pub fn generate() -> Result<Self, Unspecified> { |
223 | 0 | let evp_pkey = generate_key()?; |
224 | | |
225 | 0 | let mut public_key = [0u8; ED25519_PUBLIC_KEY_LEN]; |
226 | 0 | let out_len: usize = evp_pkey |
227 | 0 | .as_const() |
228 | 0 | .marshal_raw_public_to_buffer(&mut public_key)?; |
229 | 0 | debug_assert_eq!(public_key.len(), out_len); |
230 | | |
231 | 0 | Ok(Self { |
232 | 0 | public_key: PublicKey { |
233 | 0 | public_key_bytes: public_key, |
234 | 0 | evp_pkey: evp_pkey.clone(), |
235 | 0 | }, |
236 | 0 | evp_pkey, |
237 | 0 | }) |
238 | 0 | } |
239 | | |
240 | | /// Generates a new key pair and returns the key pair serialized as a |
241 | | /// PKCS#8 document. |
242 | | /// |
243 | | /// The PKCS#8 document will be a v2 `OneAsymmetricKey` with the public key, |
244 | | /// as described in [RFC 5958 Section 2]; see [RFC 8410 Section 10.3] for an |
245 | | /// example. |
246 | | /// |
247 | | /// [RFC 5958 Section 2]: https://tools.ietf.org/html/rfc5958#section-2 |
248 | | /// [RFC 8410 Section 10.3]: https://tools.ietf.org/html/rfc8410#section-10.3 |
249 | | /// |
250 | | /// # *ring* Compatibility |
251 | | /// The ring 0.16.x API did not produce encoded v2 documents that were compliant with RFC 5958. |
252 | | /// The aws-lc-ring implementation produces PKCS#8 v2 encoded documents that are compliant per |
253 | | /// the RFC specification. |
254 | | /// |
255 | | /// Our implementation ignores the `SecureRandom` parameter. |
256 | | /// |
257 | | // # FIPS |
258 | | // This function must not be used. |
259 | | // |
260 | | /// # Errors |
261 | | /// `error::Unspecified` if `rng` cannot provide enough bits or if there's an internal error. |
262 | 0 | pub fn generate_pkcs8(_rng: &dyn SecureRandom) -> Result<Document, Unspecified> { |
263 | 0 | let evp_pkey = generate_key()?; |
264 | 0 | Ok(Document::new( |
265 | 0 | evp_pkey |
266 | 0 | .as_const() |
267 | 0 | .marshal_rfc5208_private_key(Version::V2)?, |
268 | | )) |
269 | 0 | } |
270 | | |
271 | | /// Serializes this `Ed25519KeyPair` into a PKCS#8 v2 document. |
272 | | /// |
273 | | /// # Errors |
274 | | /// `error::Unspecified` on internal error. |
275 | | /// |
276 | 0 | pub fn to_pkcs8(&self) -> Result<Document, Unspecified> { |
277 | 0 | Ok(Document::new( |
278 | 0 | self.evp_pkey |
279 | 0 | .as_const() |
280 | 0 | .marshal_rfc5208_private_key(Version::V2)?, |
281 | | )) |
282 | 0 | } |
283 | | |
284 | | /// Generates a `Ed25519KeyPair` using the `rng` provided, then serializes that key as a |
285 | | /// PKCS#8 document. |
286 | | /// |
287 | | /// The PKCS#8 document will be a v1 `PrivateKeyInfo` structure (RFC5208). Use this method |
288 | | /// when needing to produce documents that are compatible with the OpenSSL CLI. |
289 | | /// |
290 | | /// # *ring* Compatibility |
291 | | /// Our implementation ignores the `SecureRandom` parameter. |
292 | | /// |
293 | | // # FIPS |
294 | | // This function must not be used. |
295 | | // |
296 | | /// # Errors |
297 | | /// `error::Unspecified` if `rng` cannot provide enough bits or if there's an internal error. |
298 | 0 | pub fn generate_pkcs8v1(_rng: &dyn SecureRandom) -> Result<Document, Unspecified> { |
299 | 0 | let evp_pkey = generate_key()?; |
300 | 0 | Ok(Document::new( |
301 | 0 | evp_pkey |
302 | 0 | .as_const() |
303 | 0 | .marshal_rfc5208_private_key(Version::V1)?, |
304 | | )) |
305 | 0 | } |
306 | | |
307 | | /// Serializes this `Ed25519KeyPair` into a PKCS#8 v1 document. |
308 | | /// |
309 | | /// # Errors |
310 | | /// `error::Unspecified` on internal error. |
311 | | /// |
312 | 0 | pub fn to_pkcs8v1(&self) -> Result<Document, Unspecified> { |
313 | 0 | Ok(Document::new( |
314 | 0 | self.evp_pkey |
315 | 0 | .as_const() |
316 | 0 | .marshal_rfc5208_private_key(Version::V1)?, |
317 | | )) |
318 | 0 | } |
319 | | |
320 | | /// Constructs an Ed25519 key pair from the private key seed `seed` and its |
321 | | /// public key `public_key`. |
322 | | /// |
323 | | /// It is recommended to use `Ed25519KeyPair::from_pkcs8()` instead. |
324 | | /// |
325 | | /// The private and public keys will be verified to be consistent with each |
326 | | /// other. This helps avoid misuse of the key (e.g. accidentally swapping |
327 | | /// the private key and public key, or using the wrong private key for the |
328 | | /// public key). This also detects any corruption of the public or private |
329 | | /// key. |
330 | | /// |
331 | | /// # Errors |
332 | | /// `error::KeyRejected` if parse error, or if key is otherwise unacceptable. |
333 | 0 | pub fn from_seed_and_public_key(seed: &[u8], public_key: &[u8]) -> Result<Self, KeyRejected> { |
334 | 0 | let this = Self::from_seed_unchecked(seed)?; |
335 | | |
336 | 0 | constant_time::verify_slices_are_equal(public_key, &this.public_key.public_key_bytes) |
337 | 0 | .map_err(|_| KeyRejected::inconsistent_components())?; |
338 | 0 | Ok(this) |
339 | 0 | } |
340 | | |
341 | | /// Constructs an Ed25519 key pair from the private key seed `seed`. |
342 | | /// |
343 | | /// It is recommended to use `Ed25519KeyPair::from_pkcs8()` instead. If the public key is |
344 | | /// available, prefer to use `Ed25519KeyPair::from_seed_and_public_key()` as it will verify |
345 | | /// the validity of the key pair. |
346 | | /// |
347 | | /// CAUTION: Both an Ed25519 seed and its public key are 32-bytes. If the bytes of a public key |
348 | | /// are provided this function will create an (effectively) invalid `Ed25519KeyPair`. This |
349 | | /// problem is undetectable by the API. |
350 | | /// |
351 | | /// # Errors |
352 | | /// `error::KeyRejected` if parse error, or if key is otherwise unacceptable. |
353 | 0 | pub fn from_seed_unchecked(seed: &[u8]) -> Result<Self, KeyRejected> { |
354 | 0 | if seed.len() < ED25519_SEED_LEN { |
355 | 0 | return Err(KeyRejected::inconsistent_components()); |
356 | 0 | } |
357 | | |
358 | 0 | let evp_pkey = LcPtr::<EVP_PKEY>::parse_raw_private_key(seed, EVP_PKEY_ED25519)?; |
359 | | |
360 | 0 | let mut derived_public_key = [0u8; ED25519_PUBLIC_KEY_LEN]; |
361 | 0 | let out_len: usize = evp_pkey |
362 | 0 | .as_const() |
363 | 0 | .marshal_raw_public_to_buffer(&mut derived_public_key)?; |
364 | 0 | debug_assert_eq!(derived_public_key.len(), out_len); |
365 | | |
366 | 0 | Ok(Self { |
367 | 0 | public_key: PublicKey { |
368 | 0 | public_key_bytes: derived_public_key, |
369 | 0 | evp_pkey: evp_pkey.clone(), |
370 | 0 | }, |
371 | 0 | evp_pkey, |
372 | 0 | }) |
373 | 0 | } |
374 | | |
375 | | /// Constructs an Ed25519 key pair by parsing an unencrypted PKCS#8 v1 or v2 |
376 | | /// Ed25519 private key. |
377 | | /// |
378 | | /// `openssl genpkey -algorithm ED25519` generates PKCS#8 v1 keys. |
379 | | /// |
380 | | /// # Ring Compatibility |
381 | | /// * This method accepts either v1 or v2 encoded keys, if a v2 encoded key is provided, with the |
382 | | /// public key component present, it will be verified to match the one derived from the |
383 | | /// encoded private key. |
384 | | /// * The ring 0.16.x API did not produce encoded v2 documents that were compliant with RFC 5958. |
385 | | /// The aws-lc-ring implementation produces PKCS#8 v2 encoded documents that are compliant per |
386 | | /// the RFC specification. |
387 | | /// |
388 | | /// # Errors |
389 | | /// `error::KeyRejected` on parse error, or if key is otherwise unacceptable. |
390 | 0 | pub fn from_pkcs8(pkcs8: &[u8]) -> Result<Self, KeyRejected> { |
391 | 0 | Self::parse_pkcs8(pkcs8) |
392 | 0 | } |
393 | | |
394 | | /// Constructs an Ed25519 key pair by parsing an unencrypted PKCS#8 v1 or v2 |
395 | | /// Ed25519 private key. |
396 | | /// |
397 | | /// `openssl genpkey -algorithm ED25519` generates PKCS# v1 keys. |
398 | | /// |
399 | | /// # Ring Compatibility |
400 | | /// * This method accepts either v1 or v2 encoded keys, if a v2 encoded key is provided, with the |
401 | | /// public key component present, it will be verified to match the one derived from the |
402 | | /// encoded private key. |
403 | | /// * The ring 0.16.x API did not produce encoded v2 documents that were compliant with RFC 5958. |
404 | | /// The aws-lc-ring implementation produces PKCS#8 v2 encoded documents that are compliant per |
405 | | /// the RFC specification. |
406 | | /// |
407 | | /// # Errors |
408 | | /// `error::KeyRejected` on parse error, or if key is otherwise unacceptable. |
409 | 0 | pub fn from_pkcs8_maybe_unchecked(pkcs8: &[u8]) -> Result<Self, KeyRejected> { |
410 | 0 | Self::parse_pkcs8(pkcs8) |
411 | 0 | } |
412 | | |
413 | 0 | fn parse_pkcs8(pkcs8: &[u8]) -> Result<Self, KeyRejected> { |
414 | 0 | let evp_pkey = LcPtr::<EVP_PKEY>::parse_rfc5208_private_key(pkcs8, EVP_PKEY_ED25519)?; |
415 | | |
416 | 0 | evp_pkey.as_const().validate_as_ed25519()?; |
417 | | |
418 | 0 | let mut public_key = [0u8; ED25519_PUBLIC_KEY_LEN]; |
419 | 0 | let out_len: usize = evp_pkey |
420 | 0 | .as_const() |
421 | 0 | .marshal_raw_public_to_buffer(&mut public_key)?; |
422 | 0 | debug_assert_eq!(public_key.len(), out_len); |
423 | | |
424 | 0 | Ok(Self { |
425 | 0 | public_key: PublicKey { |
426 | 0 | public_key_bytes: public_key, |
427 | 0 | evp_pkey: evp_pkey.clone(), |
428 | 0 | }, |
429 | 0 | evp_pkey, |
430 | 0 | }) |
431 | 0 | } |
432 | | |
433 | | /// Returns the signature of the message msg. |
434 | | /// |
435 | | // # FIPS |
436 | | // This method must not be used. |
437 | | // |
438 | | /// # Panics |
439 | | /// Panics if the message is unable to be signed |
440 | | #[inline] |
441 | | #[must_use] |
442 | 0 | pub fn sign(&self, msg: &[u8]) -> Signature { |
443 | 0 | Self::try_sign(self, msg).expect("ED25519 signing failed") |
444 | 0 | } Unexecuted instantiation: <aws_lc_rs::ed25519::Ed25519KeyPair>::sign Unexecuted instantiation: <aws_lc_rs::ed25519::Ed25519KeyPair>::sign |
445 | | |
446 | | /// Returns the signature of the message `msg`. |
447 | | /// |
448 | | // # FIPS |
449 | | // This method must not be used. |
450 | | // |
451 | | /// # Errors |
452 | | /// Returns `error::Unspecified` if the signing operation fails. |
453 | | #[inline] |
454 | 0 | pub fn try_sign(&self, msg: &[u8]) -> Result<Signature, Unspecified> { |
455 | 0 | let sig_bytes = self.evp_pkey.sign(msg, None, No_EVP_PKEY_CTX_consumer)?; |
456 | | |
457 | 0 | Ok(Signature::new(|slice| { |
458 | 0 | slice[0..ED25519_SIGNATURE_LEN].copy_from_slice(&sig_bytes); |
459 | 0 | ED25519_SIGNATURE_LEN |
460 | 0 | })) Unexecuted instantiation: <aws_lc_rs::ed25519::Ed25519KeyPair>::try_sign::{closure#0}Unexecuted instantiation: <aws_lc_rs::ed25519::Ed25519KeyPair>::try_sign::{closure#0} |
461 | 0 | } Unexecuted instantiation: <aws_lc_rs::ed25519::Ed25519KeyPair>::try_sign Unexecuted instantiation: <aws_lc_rs::ed25519::Ed25519KeyPair>::try_sign |
462 | | |
463 | | /// Provides the private key "seed" for this `Ed25519` key pair. |
464 | | /// |
465 | | /// For serialization of the key pair, `Ed25519KeyPair::to_pkcs8()` is preferred. |
466 | | /// |
467 | | /// # Errors |
468 | | /// Currently the function cannot fail, but it might in future implementations. |
469 | 0 | pub fn seed(&self) -> Result<Seed<'static>, Unspecified> { |
470 | | Ok(Seed { |
471 | 0 | bytes: self |
472 | 0 | .evp_pkey |
473 | 0 | .as_const() |
474 | 0 | .marshal_raw_private_key()? |
475 | 0 | .into_boxed_slice(), |
476 | 0 | phantom: PhantomData, |
477 | | }) |
478 | 0 | } |
479 | | } |
480 | | |
481 | | impl AsDer<Pkcs8V1Der<'static>> for Ed25519KeyPair { |
482 | | /// Serializes this `Ed25519KeyPair` into a PKCS#8 v1 document. |
483 | | /// |
484 | | /// # Errors |
485 | | /// `error::Unspecified` on internal error. |
486 | 0 | fn as_der(&self) -> Result<Pkcs8V1Der<'static>, crate::error::Unspecified> { |
487 | 0 | Ok(Pkcs8V1Der::new( |
488 | 0 | self.evp_pkey |
489 | 0 | .as_const() |
490 | 0 | .marshal_rfc5208_private_key(Version::V1)?, |
491 | | )) |
492 | 0 | } |
493 | | } |
494 | | |
495 | | impl AsDer<Pkcs8V2Der<'static>> for Ed25519KeyPair { |
496 | | /// Serializes this `Ed25519KeyPair` into a PKCS#8 v1 document. |
497 | | /// |
498 | | /// # Errors |
499 | | /// `error::Unspecified` on internal error. |
500 | 0 | fn as_der(&self) -> Result<Pkcs8V2Der<'static>, crate::error::Unspecified> { |
501 | 0 | Ok(Pkcs8V2Der::new( |
502 | 0 | self.evp_pkey |
503 | 0 | .as_const() |
504 | 0 | .marshal_rfc5208_private_key(Version::V2)?, |
505 | | )) |
506 | 0 | } |
507 | | } |
508 | | |
509 | | #[cfg(test)] |
510 | | mod tests { |
511 | | use crate::ed25519::Ed25519KeyPair; |
512 | | use crate::encoding::{AsBigEndian, AsDer, Pkcs8V1Der, Pkcs8V2Der, PublicKeyX509Der}; |
513 | | use crate::rand::SystemRandom; |
514 | | use crate::signature::{KeyPair, UnparsedPublicKey, ED25519}; |
515 | | use crate::{hex, test}; |
516 | | |
517 | | #[test] |
518 | | fn test_generate() { |
519 | | const MESSAGE: &[u8] = b"test message"; |
520 | | let key_pair = Ed25519KeyPair::generate().unwrap(); |
521 | | let public_key = key_pair.public_key(); |
522 | | let signature = key_pair.sign(MESSAGE); |
523 | | let unparsed_public_key = UnparsedPublicKey::new(&ED25519, public_key.as_ref()); |
524 | | unparsed_public_key |
525 | | .verify(MESSAGE, signature.as_ref()) |
526 | | .unwrap(); |
527 | | } |
528 | | |
529 | | #[test] |
530 | | fn test_generate_pkcs8() { |
531 | | let rng = SystemRandom::new(); |
532 | | let document = Ed25519KeyPair::generate_pkcs8(&rng).unwrap(); |
533 | | let kp1: Ed25519KeyPair = Ed25519KeyPair::from_pkcs8(document.as_ref()).unwrap(); |
534 | | assert_eq!( |
535 | | document.as_ref(), |
536 | | AsDer::<Pkcs8V2Der>::as_der(&kp1).unwrap().as_ref() |
537 | | ); |
538 | | let kp2: Ed25519KeyPair = |
539 | | Ed25519KeyPair::from_pkcs8_maybe_unchecked(document.as_ref()).unwrap(); |
540 | | assert_eq!( |
541 | | kp1.seed().unwrap().as_be_bytes().unwrap().as_ref(), |
542 | | kp2.seed().unwrap().as_be_bytes().unwrap().as_ref(), |
543 | | ); |
544 | | assert_eq!(kp1.public_key.as_ref(), kp2.public_key.as_ref()); |
545 | | |
546 | | let document = Ed25519KeyPair::generate_pkcs8v1(&rng).unwrap(); |
547 | | let kp1: Ed25519KeyPair = Ed25519KeyPair::from_pkcs8(document.as_ref()).unwrap(); |
548 | | assert_eq!( |
549 | | document.as_ref(), |
550 | | AsDer::<Pkcs8V1Der>::as_der(&kp1).unwrap().as_ref() |
551 | | ); |
552 | | let kp2: Ed25519KeyPair = |
553 | | Ed25519KeyPair::from_pkcs8_maybe_unchecked(document.as_ref()).unwrap(); |
554 | | assert_eq!( |
555 | | kp1.seed().unwrap().as_be_bytes().unwrap().as_ref(), |
556 | | kp2.seed().unwrap().as_be_bytes().unwrap().as_ref(), |
557 | | ); |
558 | | assert_eq!(kp1.public_key.as_ref(), kp2.public_key.as_ref()); |
559 | | let seed = kp1.seed().unwrap(); |
560 | | assert_eq!("Ed25519Seed()", format!("{seed:?}")); |
561 | | } |
562 | | |
563 | | #[test] |
564 | | fn test_from_pkcs8() { |
565 | | struct TestCase { |
566 | | key: &'static str, |
567 | | expected_public: &'static str, |
568 | | } |
569 | | |
570 | | for case in [ |
571 | | TestCase { |
572 | | key: "302e020100300506032b6570042204209d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60", |
573 | | expected_public: "d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a", |
574 | | }, |
575 | | TestCase { |
576 | | key: "3051020101300506032b657004220420756434bd5b824753007a138d27abbc14b5cc786adb78fb62435e6419a2b2e72b8121000faccd81e57de15fa6343a7fbb43b2b93f28be6435100ae8bd633c6dfee3d198", |
577 | | expected_public: "0faccd81e57de15fa6343a7fbb43b2b93f28be6435100ae8bd633c6dfee3d198", |
578 | | }, |
579 | | TestCase { |
580 | | key: "304f020100300506032b657004220420d4ee72dbf913584ad5b6d8f1f769f8ad3afe7c28cbf1d4fbe097a88f44755842a01f301d060a2a864886f70d01090914310f0c0d437572646c6520436861697273", |
581 | | expected_public: "19bf44096984cdfe8541bac167dc3b96c85086aa30b6b6cb0c5c38ad703166e1", |
582 | | }, |
583 | | TestCase { |
584 | | key: "3072020101300506032b657004220420d4ee72dbf913584ad5b6d8f1f769f8ad3afe7c28cbf1d4fbe097a88f44755842a01f301d060a2a864886f70d01090914310f0c0d437572646c652043686169727381210019bf44096984cdfe8541bac167dc3b96c85086aa30b6b6cb0c5c38ad703166e1", |
585 | | expected_public: "19bf44096984cdfe8541bac167dc3b96c85086aa30b6b6cb0c5c38ad703166e1", |
586 | | } |
587 | | ] { |
588 | | let key_pair = Ed25519KeyPair::from_pkcs8(&test::from_dirty_hex(case.key)).unwrap(); |
589 | | assert_eq!( |
590 | | format!( |
591 | | r#"Ed25519KeyPair {{ public_key: PublicKey("{}") }}"#, |
592 | | case.expected_public |
593 | | ), |
594 | | format!("{key_pair:?}") |
595 | | ); |
596 | | let key_pair = Ed25519KeyPair::from_pkcs8_maybe_unchecked(&test::from_dirty_hex(case.key)).unwrap(); |
597 | | assert_eq!( |
598 | | format!( |
599 | | r#"Ed25519KeyPair {{ public_key: PublicKey("{}") }}"#, |
600 | | case.expected_public |
601 | | ), |
602 | | format!("{key_pair:?}") |
603 | | ); |
604 | | } |
605 | | } |
606 | | |
607 | | #[test] |
608 | | fn test_public_key_as_der_x509() { |
609 | | let key_pair = Ed25519KeyPair::from_pkcs8(&hex::decode("302e020100300506032b6570042204209d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60").unwrap()).unwrap(); |
610 | | let public_key = key_pair.public_key(); |
611 | | let x509der = AsDer::<PublicKeyX509Der>::as_der(public_key).unwrap(); |
612 | | assert_eq!( |
613 | | x509der.as_ref(), |
614 | | &[ |
615 | | 0x30, 0x2a, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70, 0x03, 0x21, 0x00, 0xd7, 0x5a, |
616 | | 0x98, 0x01, 0x82, 0xb1, 0x0a, 0xb7, 0xd5, 0x4b, 0xfe, 0xd3, 0xc9, 0x64, 0x07, 0x3a, |
617 | | 0x0e, 0xe1, 0x72, 0xf3, 0xda, 0xa6, 0x23, 0x25, 0xaf, 0x02, 0x1a, 0x68, 0xf7, 0x07, |
618 | | 0x51, 0x1a |
619 | | ] |
620 | | ); |
621 | | } |
622 | | } |