/rust/registry/src/index.crates.io-1949cf8c6b5b557f/rcgen-0.14.7/src/key_pair.rs
Line | Count | Source |
1 | | #[cfg(feature = "crypto")] |
2 | | use std::fmt; |
3 | | |
4 | | #[cfg(all(feature = "aws_lc_rs_unstable", not(feature = "fips")))] |
5 | | use aws_lc_rs::unstable::signature::PqdsaKeyPair; |
6 | | #[cfg(feature = "pem")] |
7 | | use pem::Pem; |
8 | | #[cfg(feature = "crypto")] |
9 | | use pki_types::{PrivateKeyDer, PrivatePkcs8KeyDer}; |
10 | | use yasna::{DERWriter, DERWriterSeq}; |
11 | | |
12 | | #[cfg(any(feature = "crypto", feature = "pem"))] |
13 | | use crate::error::ExternalError; |
14 | | #[cfg(all(feature = "crypto", feature = "aws_lc_rs"))] |
15 | | use crate::ring_like::ecdsa_from_private_key_der; |
16 | | #[cfg(all(feature = "crypto", feature = "aws_lc_rs"))] |
17 | | use crate::ring_like::rsa::KeySize; |
18 | | #[cfg(feature = "crypto")] |
19 | | use crate::ring_like::{ |
20 | | error as ring_error, |
21 | | rand::SystemRandom, |
22 | | signature::{ |
23 | | self, EcdsaKeyPair, Ed25519KeyPair, KeyPair as RingKeyPair, RsaEncoding, RsaKeyPair, |
24 | | }, |
25 | | {ecdsa_from_pkcs8, rsa_key_pair_public_modulus_len}, |
26 | | }; |
27 | | use crate::sign_algo::SignatureAlgorithm; |
28 | | #[cfg(feature = "crypto")] |
29 | | use crate::sign_algo::{algo::*, SignAlgo}; |
30 | | use crate::Error; |
31 | | #[cfg(feature = "pem")] |
32 | | use crate::ENCODE_CONFIG; |
33 | | |
34 | | /// A key pair variant |
35 | | #[allow(clippy::large_enum_variant)] |
36 | | #[cfg(feature = "crypto")] |
37 | | pub(crate) enum KeyPairKind { |
38 | | /// A Ecdsa key pair |
39 | | Ec(EcdsaKeyPair), |
40 | | /// A Ed25519 key pair |
41 | | Ed(Ed25519KeyPair), |
42 | | /// A Pqdsa key pair |
43 | | #[cfg(all(feature = "aws_lc_rs_unstable", not(feature = "fips")))] |
44 | | Pq(PqdsaKeyPair), |
45 | | /// A RSA key pair |
46 | | Rsa(RsaKeyPair, &'static dyn RsaEncoding), |
47 | | } |
48 | | |
49 | | #[cfg(feature = "crypto")] |
50 | | impl fmt::Debug for KeyPairKind { |
51 | 0 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
52 | 0 | match self { |
53 | 0 | Self::Ec(key_pair) => write!(f, "{key_pair:?}"), |
54 | 0 | Self::Ed(key_pair) => write!(f, "{key_pair:?}"), |
55 | | #[cfg(all(feature = "aws_lc_rs_unstable", not(feature = "fips")))] |
56 | | Self::Pq(key_pair) => write!(f, "{key_pair:?}"), |
57 | 0 | Self::Rsa(key_pair, _) => write!(f, "{key_pair:?}"), |
58 | | } |
59 | 0 | } |
60 | | } |
61 | | |
62 | | /// A key pair used to sign certificates and CSRs |
63 | | #[cfg(feature = "crypto")] |
64 | | pub struct KeyPair { |
65 | | pub(crate) kind: KeyPairKind, |
66 | | pub(crate) alg: &'static SignatureAlgorithm, |
67 | | pub(crate) serialized_der: Vec<u8>, |
68 | | } |
69 | | |
70 | | #[cfg(feature = "crypto")] |
71 | | impl fmt::Debug for KeyPair { |
72 | 0 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
73 | 0 | f.debug_struct("KeyPair") |
74 | 0 | .field("kind", &self.kind) |
75 | 0 | .field("alg", &self.alg) |
76 | 0 | .field("serialized_der", &"[secret key elided]") |
77 | 0 | .finish() |
78 | 0 | } |
79 | | } |
80 | | |
81 | | #[cfg(feature = "crypto")] |
82 | | impl KeyPair { |
83 | | /// Generate a new random [`PKCS_ECDSA_P256_SHA256`] key pair |
84 | | #[cfg(feature = "crypto")] |
85 | 0 | pub fn generate() -> Result<Self, Error> { |
86 | 0 | Self::generate_for(&PKCS_ECDSA_P256_SHA256) |
87 | 0 | } |
88 | | |
89 | | /// Generate a new random key pair for the specified signature algorithm |
90 | | /// |
91 | | /// If you're not sure which algorithm to use, [`PKCS_ECDSA_P256_SHA256`] is a good choice. |
92 | | /// If passed an RSA signature algorithm, it depends on the backend whether we return |
93 | | /// a generated key or an error for key generation being unavailable. |
94 | | /// Currently, only `aws-lc-rs` supports RSA key generation. |
95 | | #[cfg(feature = "crypto")] |
96 | 0 | pub fn generate_for(alg: &'static SignatureAlgorithm) -> Result<Self, Error> { |
97 | 0 | let rng = &SystemRandom::new(); |
98 | | |
99 | 0 | match alg.sign_alg { |
100 | 0 | SignAlgo::EcDsa(sign_alg) => { |
101 | 0 | let key_pair_doc = EcdsaKeyPair::generate_pkcs8(sign_alg, rng)._err()?; |
102 | 0 | let key_pair_serialized = key_pair_doc.as_ref().to_vec(); |
103 | | |
104 | 0 | let key_pair = ecdsa_from_pkcs8(sign_alg, key_pair_doc.as_ref(), rng).unwrap(); |
105 | 0 | Ok(KeyPair { |
106 | 0 | kind: KeyPairKind::Ec(key_pair), |
107 | 0 | alg, |
108 | 0 | serialized_der: key_pair_serialized, |
109 | 0 | }) |
110 | | }, |
111 | 0 | SignAlgo::EdDsa(_sign_alg) => { |
112 | 0 | let key_pair_doc = Ed25519KeyPair::generate_pkcs8(rng)._err()?; |
113 | 0 | let key_pair_serialized = key_pair_doc.as_ref().to_vec(); |
114 | | |
115 | 0 | let key_pair = Ed25519KeyPair::from_pkcs8(key_pair_doc.as_ref()).unwrap(); |
116 | 0 | Ok(KeyPair { |
117 | 0 | kind: KeyPairKind::Ed(key_pair), |
118 | 0 | alg, |
119 | 0 | serialized_der: key_pair_serialized, |
120 | 0 | }) |
121 | | }, |
122 | | #[cfg(all(feature = "aws_lc_rs_unstable", not(feature = "fips")))] |
123 | | SignAlgo::PqDsa(sign_alg) => { |
124 | | let key_pair = PqdsaKeyPair::generate(sign_alg)._err()?; |
125 | | let key_pair_serialized = key_pair.to_pkcs8()._err()?.as_ref().to_vec(); |
126 | | |
127 | | Ok(KeyPair { |
128 | | kind: KeyPairKind::Pq(key_pair), |
129 | | alg, |
130 | | serialized_der: key_pair_serialized, |
131 | | }) |
132 | | }, |
133 | | #[cfg(feature = "aws_lc_rs")] |
134 | 0 | SignAlgo::Rsa(sign_alg) => Self::generate_rsa_inner(alg, sign_alg, KeySize::Rsa2048), |
135 | | // Ring doesn't have RSA key generation yet: |
136 | | // https://github.com/briansmith/ring/issues/219 |
137 | | // https://github.com/briansmith/ring/pull/733 |
138 | | #[cfg(all(feature = "ring", not(feature = "aws_lc_rs")))] |
139 | | SignAlgo::Rsa(_sign_alg) => Err(Error::KeyGenerationUnavailable), |
140 | | } |
141 | 0 | } |
142 | | |
143 | | /// Generates a new random RSA key pair for the specified key size |
144 | | /// |
145 | | /// If passed a signature algorithm that is not RSA, it will return |
146 | | /// [`Error::KeyGenerationUnavailable`]. |
147 | | #[cfg(all(feature = "crypto", feature = "aws_lc_rs"))] |
148 | 0 | pub fn generate_rsa_for( |
149 | 0 | alg: &'static SignatureAlgorithm, |
150 | 0 | key_size: RsaKeySize, |
151 | 0 | ) -> Result<Self, Error> { |
152 | 0 | match alg.sign_alg { |
153 | 0 | SignAlgo::Rsa(sign_alg) => { |
154 | 0 | let key_size = match key_size { |
155 | 0 | RsaKeySize::_2048 => KeySize::Rsa2048, |
156 | 0 | RsaKeySize::_3072 => KeySize::Rsa3072, |
157 | 0 | RsaKeySize::_4096 => KeySize::Rsa4096, |
158 | | }; |
159 | 0 | Self::generate_rsa_inner(alg, sign_alg, key_size) |
160 | | }, |
161 | 0 | _ => Err(Error::KeyGenerationUnavailable), |
162 | | } |
163 | 0 | } |
164 | | |
165 | | #[cfg(all(feature = "crypto", feature = "aws_lc_rs"))] |
166 | 0 | fn generate_rsa_inner( |
167 | 0 | alg: &'static SignatureAlgorithm, |
168 | 0 | sign_alg: &'static dyn RsaEncoding, |
169 | 0 | key_size: KeySize, |
170 | 0 | ) -> Result<Self, Error> { |
171 | | use aws_lc_rs::encoding::AsDer; |
172 | 0 | let key_pair = RsaKeyPair::generate(key_size)._err()?; |
173 | 0 | let key_pair_serialized = key_pair.as_der()._err()?.as_ref().to_vec(); |
174 | | |
175 | 0 | Ok(KeyPair { |
176 | 0 | kind: KeyPairKind::Rsa(key_pair, sign_alg), |
177 | 0 | alg, |
178 | 0 | serialized_der: key_pair_serialized, |
179 | 0 | }) |
180 | 0 | } |
181 | | |
182 | | /// Returns the key pair's signature algorithm |
183 | 0 | pub fn algorithm(&self) -> &'static SignatureAlgorithm { |
184 | 0 | self.alg |
185 | 0 | } |
186 | | |
187 | | /// Parses the key pair from the ASCII PEM format |
188 | | /// |
189 | | /// If `aws_lc_rs` feature is used, then the key must be a DER-encoded plaintext private key; as specified in PKCS #8/RFC 5958, SEC1/RFC 5915, or PKCS#1/RFC 3447; |
190 | | /// Appears as "PRIVATE KEY", "RSA PRIVATE KEY", or "EC PRIVATE KEY" in PEM files. |
191 | | /// |
192 | | /// Otherwise if the `ring` feature is used, then the key must be a DER-encoded plaintext private key; as specified in PKCS #8/RFC 5958; |
193 | | /// Appears as "PRIVATE KEY" in PEM files. |
194 | | #[cfg(all(feature = "pem", feature = "crypto"))] |
195 | 0 | pub fn from_pem(pem_str: &str) -> Result<Self, Error> { |
196 | 0 | let private_key = pem::parse(pem_str)._err()?; |
197 | 0 | Self::try_from(private_key.contents()) |
198 | 0 | } |
199 | | |
200 | | /// Obtains the key pair from a DER formatted key |
201 | | /// using the specified [`SignatureAlgorithm`] |
202 | | /// |
203 | | /// The key must be a DER-encoded plaintext private key; as specified in PKCS #8/RFC 5958; |
204 | | /// |
205 | | /// Appears as "PRIVATE KEY" in PEM files |
206 | | /// Same as [from_pkcs8_pem_and_sign_algo](Self::from_pkcs8_pem_and_sign_algo). |
207 | | #[cfg(all(feature = "pem", feature = "crypto"))] |
208 | 0 | pub fn from_pkcs8_pem_and_sign_algo( |
209 | 0 | pem_str: &str, |
210 | 0 | alg: &'static SignatureAlgorithm, |
211 | 0 | ) -> Result<Self, Error> { |
212 | 0 | let private_key = pem::parse(pem_str)._err()?; |
213 | 0 | let private_key_der: &[_] = private_key.contents(); |
214 | 0 | Self::from_pkcs8_der_and_sign_algo(&PrivatePkcs8KeyDer::from(private_key_der), alg) |
215 | 0 | } |
216 | | |
217 | | /// Obtains the key pair from a DER formatted key using the specified [`SignatureAlgorithm`] |
218 | | /// |
219 | | /// If you have a [`PrivatePkcs8KeyDer`], you can usually rely on the [`TryFrom`] implementation |
220 | | /// to obtain a [`KeyPair`] -- it will determine the correct [`SignatureAlgorithm`] for you. |
221 | | /// However, sometimes multiple signature algorithms fit for the same DER key. In those instances, |
222 | | /// you can use this function to precisely specify the `SignatureAlgorithm`. |
223 | | /// |
224 | | /// [`rustls_pemfile::private_key()`] is often used to obtain a [`PrivateKeyDer`] from PEM |
225 | | /// input. If the obtained [`PrivateKeyDer`] is a `Pkcs8` variant, you can use its contents |
226 | | /// as input for this function. Alternatively, if you already have a byte slice containing DER, |
227 | | /// it can trivially be converted into [`PrivatePkcs8KeyDer`] using the [`Into`] trait. |
228 | | /// |
229 | | /// [`rustls_pemfile::private_key()`]: https://docs.rs/rustls-pemfile/latest/rustls_pemfile/fn.private_key.html |
230 | | /// [`PrivateKeyDer`]: https://docs.rs/rustls-pki-types/latest/rustls_pki_types/enum.PrivateKeyDer.html |
231 | | #[cfg(feature = "crypto")] |
232 | 0 | pub fn from_pkcs8_der_and_sign_algo( |
233 | 0 | pkcs8: &PrivatePkcs8KeyDer<'_>, |
234 | 0 | alg: &'static SignatureAlgorithm, |
235 | 0 | ) -> Result<Self, Error> { |
236 | 0 | let rng = &SystemRandom::new(); |
237 | 0 | let serialized_der = pkcs8.secret_pkcs8_der().to_vec(); |
238 | | |
239 | 0 | let kind = if alg == &PKCS_ED25519 { |
240 | 0 | KeyPairKind::Ed(Ed25519KeyPair::from_pkcs8_maybe_unchecked(&serialized_der)._err()?) |
241 | 0 | } else if alg == &PKCS_ECDSA_P256_SHA256 { |
242 | 0 | KeyPairKind::Ec(ecdsa_from_pkcs8( |
243 | 0 | &signature::ECDSA_P256_SHA256_ASN1_SIGNING, |
244 | 0 | &serialized_der, |
245 | 0 | rng, |
246 | 0 | )?) |
247 | 0 | } else if alg == &PKCS_ECDSA_P384_SHA384 { |
248 | 0 | KeyPairKind::Ec(ecdsa_from_pkcs8( |
249 | 0 | &signature::ECDSA_P384_SHA384_ASN1_SIGNING, |
250 | 0 | &serialized_der, |
251 | 0 | rng, |
252 | 0 | )?) |
253 | 0 | } else if alg == &PKCS_RSA_SHA256 { |
254 | 0 | let rsakp = RsaKeyPair::from_pkcs8(&serialized_der)._err()?; |
255 | 0 | KeyPairKind::Rsa(rsakp, &signature::RSA_PKCS1_SHA256) |
256 | 0 | } else if alg == &PKCS_RSA_SHA384 { |
257 | 0 | let rsakp = RsaKeyPair::from_pkcs8(&serialized_der)._err()?; |
258 | 0 | KeyPairKind::Rsa(rsakp, &signature::RSA_PKCS1_SHA384) |
259 | 0 | } else if alg == &PKCS_RSA_SHA512 { |
260 | 0 | let rsakp = RsaKeyPair::from_pkcs8(&serialized_der)._err()?; |
261 | 0 | KeyPairKind::Rsa(rsakp, &signature::RSA_PKCS1_SHA512) |
262 | 0 | } else if alg == &PKCS_RSA_PSS_SHA256 { |
263 | 0 | let rsakp = RsaKeyPair::from_pkcs8(&serialized_der)._err()?; |
264 | 0 | KeyPairKind::Rsa(rsakp, &signature::RSA_PSS_SHA256) |
265 | | } else { |
266 | | #[cfg(feature = "aws_lc_rs")] |
267 | 0 | if alg == &PKCS_ECDSA_P521_SHA256 { |
268 | 0 | KeyPairKind::Ec(ecdsa_from_pkcs8( |
269 | 0 | &signature::ECDSA_P521_SHA256_ASN1_SIGNING, |
270 | 0 | &serialized_der, |
271 | 0 | rng, |
272 | 0 | )?) |
273 | 0 | } else if alg == &PKCS_ECDSA_P521_SHA384 { |
274 | 0 | KeyPairKind::Ec(ecdsa_from_pkcs8( |
275 | 0 | &signature::ECDSA_P521_SHA384_ASN1_SIGNING, |
276 | 0 | &serialized_der, |
277 | 0 | rng, |
278 | 0 | )?) |
279 | 0 | } else if alg == &PKCS_ECDSA_P521_SHA512 { |
280 | 0 | KeyPairKind::Ec(ecdsa_from_pkcs8( |
281 | 0 | &signature::ECDSA_P521_SHA512_ASN1_SIGNING, |
282 | 0 | &serialized_der, |
283 | 0 | rng, |
284 | 0 | )?) |
285 | | } else { |
286 | 0 | panic!("Unknown SignatureAlgorithm specified!"); |
287 | | } |
288 | | |
289 | | #[cfg(all(feature = "ring", not(feature = "aws_lc_rs")))] |
290 | | panic!("Unknown SignatureAlgorithm specified!"); |
291 | | }; |
292 | | |
293 | 0 | Ok(KeyPair { |
294 | 0 | kind, |
295 | 0 | alg, |
296 | 0 | serialized_der, |
297 | 0 | }) |
298 | 0 | } |
299 | | |
300 | | /// Obtains the key pair from a PEM formatted key |
301 | | /// using the specified [`SignatureAlgorithm`] |
302 | | /// |
303 | | /// If `aws_lc_rs` feature is used, then the key must be a DER-encoded plaintext private key; as specified in PKCS #8/RFC 5958, SEC1/RFC 5915, or PKCS#1/RFC 3447; |
304 | | /// Appears as "PRIVATE KEY", "RSA PRIVATE KEY", or "EC PRIVATE KEY" in PEM files. |
305 | | /// |
306 | | /// Otherwise if the `ring` feature is used, then the key must be a DER-encoded plaintext private key; as specified in PKCS #8/RFC 5958; |
307 | | /// Appears as "PRIVATE KEY" in PEM files. |
308 | | /// |
309 | | /// Same as [from_pem_and_sign_algo](Self::from_pem_and_sign_algo). |
310 | | #[cfg(all(feature = "pem", feature = "crypto"))] |
311 | 0 | pub fn from_pem_and_sign_algo( |
312 | 0 | pem_str: &str, |
313 | 0 | alg: &'static SignatureAlgorithm, |
314 | 0 | ) -> Result<Self, Error> { |
315 | 0 | let private_key = pem::parse(pem_str)._err()?; |
316 | 0 | let private_key: &[_] = private_key.contents(); |
317 | 0 | Self::from_der_and_sign_algo( |
318 | 0 | &PrivateKeyDer::try_from(private_key).map_err(|_| Error::CouldNotParseKeyPair)?, |
319 | 0 | alg, |
320 | | ) |
321 | 0 | } |
322 | | |
323 | | /// Obtains the key pair from a DER formatted key |
324 | | /// using the specified [`SignatureAlgorithm`] |
325 | | /// |
326 | | /// Note that using the `ring` feature, this function only support [`PrivateKeyDer::Pkcs8`] variant. |
327 | | /// Consider using the `aws_lc_rs` features to support [`PrivateKeyDer`] fully. |
328 | | /// |
329 | | /// If you have a [`PrivateKeyDer`], you can usually rely on the [`TryFrom`] implementation |
330 | | /// to obtain a [`KeyPair`] -- it will determine the correct [`SignatureAlgorithm`] for you. |
331 | | /// However, sometimes multiple signature algorithms fit for the same DER key. In those instances, |
332 | | /// you can use this function to precisely specify the `SignatureAlgorithm`. |
333 | | /// |
334 | | /// You can use [`rustls_pemfile::private_key`] to get the `key` input. If |
335 | | /// you have already a byte slice, just calling `try_into()` will convert it to a [`PrivateKeyDer`]. |
336 | | /// |
337 | | /// [`rustls_pemfile::private_key`]: https://docs.rs/rustls-pemfile/latest/rustls_pemfile/fn.private_key.html |
338 | | #[cfg(feature = "crypto")] |
339 | 0 | pub fn from_der_and_sign_algo( |
340 | 0 | key: &PrivateKeyDer<'_>, |
341 | 0 | alg: &'static SignatureAlgorithm, |
342 | 0 | ) -> Result<Self, Error> { |
343 | | #[cfg(all(feature = "ring", not(feature = "aws_lc_rs")))] |
344 | | { |
345 | | if let PrivateKeyDer::Pkcs8(key) = key { |
346 | | Self::from_pkcs8_der_and_sign_algo(key, alg) |
347 | | } else { |
348 | | Err(Error::CouldNotParseKeyPair) |
349 | | } |
350 | | } |
351 | | #[cfg(feature = "aws_lc_rs")] |
352 | | { |
353 | 0 | let is_pkcs8 = matches!(key, PrivateKeyDer::Pkcs8(_)); |
354 | | |
355 | 0 | let rsa_key_pair_from = if is_pkcs8 { |
356 | 0 | RsaKeyPair::from_pkcs8 |
357 | 0 | } else { |
358 | 0 | RsaKeyPair::from_der |
359 | 0 | }; |
360 | | |
361 | 0 | let serialized_der = key.secret_der().to_vec(); |
362 | | |
363 | 0 | let kind = if alg == &PKCS_ED25519 { |
364 | 0 | KeyPairKind::Ed(Ed25519KeyPair::from_pkcs8_maybe_unchecked(&serialized_der)._err()?) |
365 | 0 | } else if alg == &PKCS_ECDSA_P256_SHA256 { |
366 | 0 | KeyPairKind::Ec(ecdsa_from_private_key_der( |
367 | 0 | &signature::ECDSA_P256_SHA256_ASN1_SIGNING, |
368 | 0 | &serialized_der, |
369 | 0 | )?) |
370 | 0 | } else if alg == &PKCS_ECDSA_P384_SHA384 { |
371 | 0 | KeyPairKind::Ec(ecdsa_from_private_key_der( |
372 | 0 | &signature::ECDSA_P384_SHA384_ASN1_SIGNING, |
373 | 0 | &serialized_der, |
374 | 0 | )?) |
375 | 0 | } else if alg == &PKCS_ECDSA_P521_SHA512 { |
376 | 0 | KeyPairKind::Ec(ecdsa_from_private_key_der( |
377 | 0 | &signature::ECDSA_P521_SHA512_ASN1_SIGNING, |
378 | 0 | &serialized_der, |
379 | 0 | )?) |
380 | 0 | } else if alg == &PKCS_RSA_SHA256 { |
381 | 0 | let rsakp = rsa_key_pair_from(&serialized_der)._err()?; |
382 | 0 | KeyPairKind::Rsa(rsakp, &signature::RSA_PKCS1_SHA256) |
383 | 0 | } else if alg == &PKCS_RSA_SHA384 { |
384 | 0 | let rsakp = rsa_key_pair_from(&serialized_der)._err()?; |
385 | 0 | KeyPairKind::Rsa(rsakp, &signature::RSA_PKCS1_SHA384) |
386 | 0 | } else if alg == &PKCS_RSA_SHA512 { |
387 | 0 | let rsakp = rsa_key_pair_from(&serialized_der)._err()?; |
388 | 0 | KeyPairKind::Rsa(rsakp, &signature::RSA_PKCS1_SHA512) |
389 | 0 | } else if alg == &PKCS_RSA_PSS_SHA256 { |
390 | 0 | let rsakp = rsa_key_pair_from(&serialized_der)._err()?; |
391 | 0 | KeyPairKind::Rsa(rsakp, &signature::RSA_PSS_SHA256) |
392 | | } else { |
393 | 0 | panic!("Unknown SignatureAlgorithm specified!"); |
394 | | }; |
395 | | |
396 | 0 | Ok(KeyPair { |
397 | 0 | kind, |
398 | 0 | alg, |
399 | 0 | serialized_der, |
400 | 0 | }) |
401 | | } |
402 | 0 | } |
403 | | |
404 | | /// Get the raw public key of this key pair |
405 | | /// |
406 | | /// The key is in raw format, as how [`KeyPair::public_key()`][public_key] |
407 | | /// would output, and how [`UnparsedPublicKey::verify()`][verify] |
408 | | /// would accept. |
409 | | /// |
410 | | /// [public_key]: crate::ring_like::signature::KeyPair::public_key() |
411 | | /// [verify]: crate::ring_like::signature::UnparsedPublicKey::verify() |
412 | 0 | pub fn public_key_raw(&self) -> &[u8] { |
413 | 0 | self.der_bytes() |
414 | 0 | } |
415 | | |
416 | | /// Check if this key pair can be used with the given signature algorithm |
417 | 0 | pub fn is_compatible(&self, signature_algorithm: &SignatureAlgorithm) -> bool { |
418 | 0 | self.alg == signature_algorithm |
419 | 0 | } |
420 | | |
421 | | /// Returns (possibly multiple) compatible [`SignatureAlgorithm`]'s |
422 | | /// that the key can be used with |
423 | 0 | pub fn compatible_algs(&self) -> impl Iterator<Item = &'static SignatureAlgorithm> { |
424 | 0 | std::iter::once(self.alg) |
425 | 0 | } |
426 | | |
427 | | /// Return the key pair's public key in PEM format |
428 | | /// |
429 | | /// The returned string can be interpreted with `openssl pkey --inform PEM -pubout -pubin -text` |
430 | | #[cfg(feature = "pem")] |
431 | 0 | pub fn public_key_pem(&self) -> String { |
432 | 0 | let contents = self.subject_public_key_info(); |
433 | 0 | let p = Pem::new("PUBLIC KEY", contents); |
434 | 0 | pem::encode_config(&p, ENCODE_CONFIG) |
435 | 0 | } |
436 | | |
437 | | /// Serializes the key pair (including the private key) in PKCS#8 format in DER |
438 | 0 | pub fn serialize_der(&self) -> Vec<u8> { |
439 | 0 | self.serialized_der.clone() |
440 | 0 | } |
441 | | |
442 | | /// Returns a reference to the serialized key pair (including the private key) |
443 | | /// in PKCS#8 format in DER |
444 | 0 | pub fn serialized_der(&self) -> &[u8] { |
445 | 0 | &self.serialized_der |
446 | 0 | } |
447 | | |
448 | | /// Serializes the key pair (including the private key) in PKCS#8 format in PEM |
449 | | #[cfg(feature = "pem")] |
450 | 0 | pub fn serialize_pem(&self) -> String { |
451 | 0 | let contents = self.serialize_der(); |
452 | 0 | let p = Pem::new("PRIVATE KEY", contents); |
453 | 0 | pem::encode_config(&p, ENCODE_CONFIG) |
454 | 0 | } |
455 | | } |
456 | | |
457 | | #[cfg(feature = "crypto")] |
458 | | impl SigningKey for KeyPair { |
459 | 0 | fn sign(&self, msg: &[u8]) -> Result<Vec<u8>, Error> { |
460 | 0 | Ok(match &self.kind { |
461 | 0 | KeyPairKind::Ec(kp) => { |
462 | 0 | let system_random = SystemRandom::new(); |
463 | 0 | let signature = kp.sign(&system_random, msg)._err()?; |
464 | 0 | signature.as_ref().to_owned() |
465 | | }, |
466 | 0 | KeyPairKind::Ed(kp) => kp.sign(msg).as_ref().to_owned(), |
467 | | #[cfg(all(feature = "aws_lc_rs_unstable", not(feature = "fips")))] |
468 | | KeyPairKind::Pq(kp) => { |
469 | | let mut signature = vec![0; kp.algorithm().signature_len()]; |
470 | | kp.sign(msg, &mut signature)._err()?; |
471 | | signature |
472 | | }, |
473 | 0 | KeyPairKind::Rsa(kp, padding_alg) => { |
474 | 0 | let system_random = SystemRandom::new(); |
475 | 0 | let mut signature = vec![0; rsa_key_pair_public_modulus_len(kp)]; |
476 | 0 | kp.sign(*padding_alg, &system_random, msg, &mut signature) |
477 | 0 | ._err()?; |
478 | 0 | signature |
479 | | }, |
480 | | }) |
481 | 0 | } |
482 | | } |
483 | | |
484 | | #[cfg(feature = "crypto")] |
485 | | impl PublicKeyData for KeyPair { |
486 | 0 | fn der_bytes(&self) -> &[u8] { |
487 | 0 | match &self.kind { |
488 | 0 | KeyPairKind::Ec(kp) => kp.public_key().as_ref(), |
489 | 0 | KeyPairKind::Ed(kp) => kp.public_key().as_ref(), |
490 | | #[cfg(all(feature = "aws_lc_rs_unstable", not(feature = "fips")))] |
491 | | KeyPairKind::Pq(kp) => kp.public_key().as_ref(), |
492 | 0 | KeyPairKind::Rsa(kp, _) => kp.public_key().as_ref(), |
493 | | } |
494 | 0 | } |
495 | | |
496 | 0 | fn algorithm(&self) -> &'static SignatureAlgorithm { |
497 | 0 | self.alg |
498 | 0 | } |
499 | | } |
500 | | |
501 | | #[cfg(feature = "crypto")] |
502 | | impl TryFrom<&[u8]> for KeyPair { |
503 | | type Error = Error; |
504 | | |
505 | 0 | fn try_from(key: &[u8]) -> Result<KeyPair, Error> { |
506 | 0 | let key = &PrivateKeyDer::try_from(key).map_err(|_| Error::CouldNotParseKeyPair)?; |
507 | | |
508 | 0 | key.try_into() |
509 | 0 | } |
510 | | } |
511 | | |
512 | | #[cfg(feature = "crypto")] |
513 | | impl TryFrom<Vec<u8>> for KeyPair { |
514 | | type Error = Error; |
515 | | |
516 | 0 | fn try_from(key: Vec<u8>) -> Result<KeyPair, Error> { |
517 | 0 | let key = &PrivateKeyDer::try_from(key).map_err(|_| Error::CouldNotParseKeyPair)?; |
518 | | |
519 | 0 | key.try_into() |
520 | 0 | } |
521 | | } |
522 | | |
523 | | #[cfg(feature = "crypto")] |
524 | | impl TryFrom<&PrivatePkcs8KeyDer<'_>> for KeyPair { |
525 | | type Error = Error; |
526 | | |
527 | 0 | fn try_from(key: &PrivatePkcs8KeyDer) -> Result<KeyPair, Error> { |
528 | 0 | key.secret_pkcs8_der().try_into() |
529 | 0 | } |
530 | | } |
531 | | |
532 | | #[cfg(feature = "crypto")] |
533 | | impl TryFrom<&PrivateKeyDer<'_>> for KeyPair { |
534 | | type Error = Error; |
535 | | |
536 | 0 | fn try_from(key: &PrivateKeyDer) -> Result<KeyPair, Error> { |
537 | | #[cfg(all(feature = "ring", not(feature = "aws_lc_rs")))] |
538 | | let (kind, alg) = { |
539 | | let PrivateKeyDer::Pkcs8(pkcs8) = key else { |
540 | | return Err(Error::CouldNotParseKeyPair); |
541 | | }; |
542 | | let pkcs8 = pkcs8.secret_pkcs8_der(); |
543 | | let rng = SystemRandom::new(); |
544 | | let (kind, alg) = if let Ok(edkp) = Ed25519KeyPair::from_pkcs8_maybe_unchecked(pkcs8) { |
545 | | (KeyPairKind::Ed(edkp), &PKCS_ED25519) |
546 | | } else if let Ok(eckp) = |
547 | | ecdsa_from_pkcs8(&signature::ECDSA_P256_SHA256_ASN1_SIGNING, pkcs8, &rng) |
548 | | { |
549 | | (KeyPairKind::Ec(eckp), &PKCS_ECDSA_P256_SHA256) |
550 | | } else if let Ok(eckp) = |
551 | | ecdsa_from_pkcs8(&signature::ECDSA_P384_SHA384_ASN1_SIGNING, pkcs8, &rng) |
552 | | { |
553 | | (KeyPairKind::Ec(eckp), &PKCS_ECDSA_P384_SHA384) |
554 | | } else if let Ok(rsakp) = RsaKeyPair::from_pkcs8(pkcs8) { |
555 | | ( |
556 | | KeyPairKind::Rsa(rsakp, &signature::RSA_PKCS1_SHA256), |
557 | | &PKCS_RSA_SHA256, |
558 | | ) |
559 | | } else { |
560 | | return Err(Error::CouldNotParseKeyPair); |
561 | | }; |
562 | | |
563 | | (kind, alg) |
564 | | }; |
565 | | #[cfg(feature = "aws_lc_rs")] |
566 | 0 | let (kind, alg) = { |
567 | 0 | let is_pkcs8 = matches!(key, PrivateKeyDer::Pkcs8(_)); |
568 | | |
569 | 0 | let key = key.secret_der(); |
570 | | |
571 | 0 | let rsa_key_pair_from = if is_pkcs8 { |
572 | 0 | RsaKeyPair::from_pkcs8 |
573 | 0 | } else { |
574 | 0 | RsaKeyPair::from_der |
575 | 0 | }; |
576 | | |
577 | 0 | let (kind, alg) = if let Ok(edkp) = Ed25519KeyPair::from_pkcs8_maybe_unchecked(key) { |
578 | 0 | (KeyPairKind::Ed(edkp), &PKCS_ED25519) |
579 | 0 | } else if let Ok(eckp) = |
580 | 0 | ecdsa_from_private_key_der(&signature::ECDSA_P256_SHA256_ASN1_SIGNING, key) |
581 | | { |
582 | 0 | (KeyPairKind::Ec(eckp), &PKCS_ECDSA_P256_SHA256) |
583 | 0 | } else if let Ok(eckp) = |
584 | 0 | ecdsa_from_private_key_der(&signature::ECDSA_P384_SHA384_ASN1_SIGNING, key) |
585 | | { |
586 | 0 | (KeyPairKind::Ec(eckp), &PKCS_ECDSA_P384_SHA384) |
587 | 0 | } else if let Ok(eckp) = |
588 | 0 | ecdsa_from_private_key_der(&signature::ECDSA_P521_SHA512_ASN1_SIGNING, key) |
589 | | { |
590 | 0 | (KeyPairKind::Ec(eckp), &PKCS_ECDSA_P521_SHA512) |
591 | 0 | } else if let Ok(rsakp) = rsa_key_pair_from(key) { |
592 | 0 | ( |
593 | 0 | KeyPairKind::Rsa(rsakp, &signature::RSA_PKCS1_SHA256), |
594 | 0 | &PKCS_RSA_SHA256, |
595 | 0 | ) |
596 | | } else { |
597 | 0 | return Err(Error::CouldNotParseKeyPair); |
598 | | }; |
599 | 0 | (kind, alg) |
600 | | }; |
601 | | |
602 | 0 | Ok(KeyPair { |
603 | 0 | kind, |
604 | 0 | alg, |
605 | 0 | serialized_der: key.secret_der().into(), |
606 | 0 | }) |
607 | 0 | } |
608 | | } |
609 | | |
610 | | #[cfg(feature = "crypto")] |
611 | | impl From<KeyPair> for PrivatePkcs8KeyDer<'static> { |
612 | 0 | fn from(val: KeyPair) -> Self { |
613 | 0 | val.serialize_der().into() |
614 | 0 | } |
615 | | } |
616 | | |
617 | | #[cfg(feature = "crypto")] |
618 | | impl From<KeyPair> for PrivateKeyDer<'static> { |
619 | 0 | fn from(val: KeyPair) -> Self { |
620 | 0 | Self::from(PrivatePkcs8KeyDer::from(val)) |
621 | 0 | } |
622 | | } |
623 | | |
624 | | /// The key size used for RSA key generation |
625 | | #[cfg(all(feature = "crypto", feature = "aws_lc_rs"))] |
626 | | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] |
627 | | #[non_exhaustive] |
628 | | pub enum RsaKeySize { |
629 | | /// 2048 bits |
630 | | _2048, |
631 | | /// 3072 bits |
632 | | _3072, |
633 | | /// 4096 bits |
634 | | _4096, |
635 | | } |
636 | | |
637 | 0 | pub(crate) fn sign_der( |
638 | 0 | key: &impl SigningKey, |
639 | 0 | f: impl FnOnce(&mut DERWriterSeq<'_>) -> Result<(), Error>, |
640 | 0 | ) -> Result<Vec<u8>, Error> { |
641 | 0 | yasna::try_construct_der(|writer| { |
642 | 0 | writer.write_sequence(|writer| { |
643 | 0 | let data = yasna::try_construct_der(|writer| writer.write_sequence(f))?; Unexecuted instantiation: rcgen::key_pair::sign_der::<rcgen::key_pair::KeyPair, <rcgen::certificate::CertificateParams>::serialize_request_with_attributes<rcgen::key_pair::KeyPair>::{closure#0}>::{closure#0}::{closure#0}::{closure#0}Unexecuted instantiation: rcgen::key_pair::sign_der::<_, _>::{closure#0}::{closure#0}::{closure#0} |
644 | 0 | writer.next().write_der(&data); |
645 | | |
646 | | // Write signatureAlgorithm |
647 | 0 | key.algorithm().write_alg_ident(writer.next()); |
648 | | |
649 | | // Write signature |
650 | 0 | let sig = key.sign(&data)?; |
651 | 0 | let writer = writer.next(); |
652 | 0 | writer.write_bitvec_bytes(&sig, sig.len() * 8); |
653 | | |
654 | 0 | Ok(()) |
655 | 0 | }) Unexecuted instantiation: rcgen::key_pair::sign_der::<rcgen::key_pair::KeyPair, <rcgen::certificate::CertificateParams>::serialize_request_with_attributes<rcgen::key_pair::KeyPair>::{closure#0}>::{closure#0}::{closure#0}Unexecuted instantiation: rcgen::key_pair::sign_der::<_, _>::{closure#0}::{closure#0} |
656 | 0 | }) Unexecuted instantiation: rcgen::key_pair::sign_der::<rcgen::key_pair::KeyPair, <rcgen::certificate::CertificateParams>::serialize_request_with_attributes<rcgen::key_pair::KeyPair>::{closure#0}>::{closure#0}Unexecuted instantiation: rcgen::key_pair::sign_der::<_, _>::{closure#0} |
657 | 0 | } Unexecuted instantiation: rcgen::key_pair::sign_der::<rcgen::key_pair::KeyPair, <rcgen::certificate::CertificateParams>::serialize_request_with_attributes<rcgen::key_pair::KeyPair>::{closure#0}>Unexecuted instantiation: rcgen::key_pair::sign_der::<_, _> |
658 | | |
659 | | impl<S: SigningKey + ?Sized> SigningKey for &S { |
660 | 0 | fn sign(&self, msg: &[u8]) -> Result<Vec<u8>, Error> { |
661 | 0 | (*self).sign(msg) |
662 | 0 | } |
663 | | } |
664 | | |
665 | | /// A key that can be used to sign messages |
666 | | pub trait SigningKey: PublicKeyData { |
667 | | /// Signs `msg` using the selected algorithm |
668 | | fn sign(&self, msg: &[u8]) -> Result<Vec<u8>, Error>; |
669 | | } |
670 | | |
671 | | #[cfg(feature = "crypto")] |
672 | | impl<T> ExternalError<T> for Result<T, ring_error::KeyRejected> { |
673 | 0 | fn _err(self) -> Result<T, Error> { |
674 | 0 | self.map_err(|e| Error::RingKeyRejected(e.to_string())) Unexecuted instantiation: <core::result::Result<aws_lc_rs::ed25519::Ed25519KeyPair, aws_lc_rs::error::KeyRejected> as rcgen::error::ExternalError<aws_lc_rs::ed25519::Ed25519KeyPair>>::_err::{closure#0}Unexecuted instantiation: <core::result::Result<aws_lc_rs::ec::key_pair::EcdsaKeyPair, aws_lc_rs::error::KeyRejected> as rcgen::error::ExternalError<aws_lc_rs::ec::key_pair::EcdsaKeyPair>>::_err::{closure#0}Unexecuted instantiation: <core::result::Result<aws_lc_rs::rsa::key::KeyPair, aws_lc_rs::error::KeyRejected> as rcgen::error::ExternalError<aws_lc_rs::rsa::key::KeyPair>>::_err::{closure#0} |
675 | 0 | } Unexecuted instantiation: <core::result::Result<aws_lc_rs::ed25519::Ed25519KeyPair, aws_lc_rs::error::KeyRejected> as rcgen::error::ExternalError<aws_lc_rs::ed25519::Ed25519KeyPair>>::_err Unexecuted instantiation: <core::result::Result<aws_lc_rs::ec::key_pair::EcdsaKeyPair, aws_lc_rs::error::KeyRejected> as rcgen::error::ExternalError<aws_lc_rs::ec::key_pair::EcdsaKeyPair>>::_err Unexecuted instantiation: <core::result::Result<aws_lc_rs::rsa::key::KeyPair, aws_lc_rs::error::KeyRejected> as rcgen::error::ExternalError<aws_lc_rs::rsa::key::KeyPair>>::_err |
676 | | } |
677 | | |
678 | | #[cfg(feature = "crypto")] |
679 | | impl<T> ExternalError<T> for Result<T, ring_error::Unspecified> { |
680 | 0 | fn _err(self) -> Result<T, Error> { |
681 | 0 | self.map_err(|_| Error::RingUnspecified) |
682 | 0 | } Unexecuted instantiation: <core::result::Result<aws_lc_rs::pkcs8::Document, aws_lc_rs::error::Unspecified> as rcgen::error::ExternalError<aws_lc_rs::pkcs8::Document>>::_err Unexecuted instantiation: <core::result::Result<aws_lc_rs::encoding::Pkcs8V1Der, aws_lc_rs::error::Unspecified> as rcgen::error::ExternalError<aws_lc_rs::encoding::Pkcs8V1Der>>::_err Unexecuted instantiation: <core::result::Result<aws_lc_rs::signature::Signature, aws_lc_rs::error::Unspecified> as rcgen::error::ExternalError<aws_lc_rs::signature::Signature>>::_err Unexecuted instantiation: <core::result::Result<aws_lc_rs::rsa::key::KeyPair, aws_lc_rs::error::Unspecified> as rcgen::error::ExternalError<aws_lc_rs::rsa::key::KeyPair>>::_err Unexecuted instantiation: <core::result::Result<(), aws_lc_rs::error::Unspecified> as rcgen::error::ExternalError<()>>::_err |
683 | | } |
684 | | |
685 | | #[cfg(feature = "pem")] |
686 | | impl<T> ExternalError<T> for Result<T, pem::PemError> { |
687 | 0 | fn _err(self) -> Result<T, Error> { |
688 | 0 | self.map_err(|e| Error::PemError(e.to_string())) |
689 | 0 | } |
690 | | } |
691 | | |
692 | | /// A public key |
693 | | #[derive(Clone, Debug, Eq, PartialEq)] |
694 | | pub struct SubjectPublicKeyInfo { |
695 | | pub(crate) alg: &'static SignatureAlgorithm, |
696 | | pub(crate) subject_public_key: Vec<u8>, |
697 | | } |
698 | | |
699 | | impl SubjectPublicKeyInfo { |
700 | | /// Create a `SubjectPublicKey` value from a PEM-encoded SubjectPublicKeyInfo string |
701 | | #[cfg(all(feature = "x509-parser", feature = "pem"))] |
702 | | pub fn from_pem(pem_str: &str) -> Result<Self, Error> { |
703 | | Self::from_der(&pem::parse(pem_str)._err()?.into_contents()) |
704 | | } |
705 | | |
706 | | /// Create a `SubjectPublicKey` value from DER-encoded SubjectPublicKeyInfo bytes |
707 | | #[cfg(feature = "x509-parser")] |
708 | | pub fn from_der(spki_der: &[u8]) -> Result<Self, Error> { |
709 | | use x509_parser::prelude::FromDer; |
710 | | use x509_parser::x509::{AlgorithmIdentifier, SubjectPublicKeyInfo}; |
711 | | |
712 | | let (rem, spki) = |
713 | | SubjectPublicKeyInfo::from_der(spki_der).map_err(|e| Error::X509(e.to_string()))?; |
714 | | if !rem.is_empty() { |
715 | | return Err(Error::X509( |
716 | | "trailing bytes in SubjectPublicKeyInfo".to_string(), |
717 | | )); |
718 | | } |
719 | | |
720 | | let alg = SignatureAlgorithm::iter() |
721 | | .find(|alg| { |
722 | | let bytes = yasna::construct_der(|writer| { |
723 | | alg.write_oids_sign_alg(writer); |
724 | | }); |
725 | | let Ok((rest, aid)) = AlgorithmIdentifier::from_der(&bytes) else { |
726 | | return false; |
727 | | }; |
728 | | if !rest.is_empty() { |
729 | | return false; |
730 | | } |
731 | | aid == spki.algorithm |
732 | | }) |
733 | | .ok_or(Error::UnsupportedSignatureAlgorithm)?; |
734 | | |
735 | | Ok(Self { |
736 | | alg, |
737 | | subject_public_key: Vec::from(spki.subject_public_key.as_ref()), |
738 | | }) |
739 | | } |
740 | | } |
741 | | |
742 | | impl PublicKeyData for SubjectPublicKeyInfo { |
743 | 0 | fn der_bytes(&self) -> &[u8] { |
744 | 0 | &self.subject_public_key |
745 | 0 | } |
746 | | |
747 | 0 | fn algorithm(&self) -> &'static SignatureAlgorithm { |
748 | 0 | self.alg |
749 | 0 | } |
750 | | } |
751 | | |
752 | | impl<K: PublicKeyData + ?Sized> PublicKeyData for &K { |
753 | 0 | fn der_bytes(&self) -> &[u8] { |
754 | 0 | (*self).der_bytes() |
755 | 0 | } |
756 | | |
757 | 0 | fn algorithm(&self) -> &'static SignatureAlgorithm { |
758 | 0 | (*self).algorithm() |
759 | 0 | } |
760 | | } |
761 | | |
762 | | /// The public key data of a key pair |
763 | | pub trait PublicKeyData { |
764 | | /// The public key data in DER format |
765 | | /// |
766 | | /// The key is formatted according to the X.509 SubjectPublicKeyInfo struct. |
767 | | /// See [RFC 5280 section 4.1](https://tools.ietf.org/html/rfc5280#section-4.1). |
768 | 0 | fn subject_public_key_info(&self) -> Vec<u8> { |
769 | 0 | yasna::construct_der(|writer| serialize_public_key_der(self, writer)) |
770 | 0 | } |
771 | | |
772 | | /// The public key in DER format |
773 | | fn der_bytes(&self) -> &[u8]; |
774 | | |
775 | | /// The algorithm used by the key pair |
776 | | fn algorithm(&self) -> &'static SignatureAlgorithm; |
777 | | } |
778 | | |
779 | 0 | pub(crate) fn serialize_public_key_der(key: &(impl PublicKeyData + ?Sized), writer: DERWriter) { |
780 | 0 | writer.write_sequence(|writer| { |
781 | 0 | key.algorithm().write_oids_sign_alg(writer.next()); |
782 | 0 | let pk = key.der_bytes(); |
783 | 0 | writer.next().write_bitvec_bytes(pk, pk.len() * 8); |
784 | 0 | }) |
785 | 0 | } |
786 | | |
787 | | #[cfg(all(test, feature = "crypto"))] |
788 | | mod test { |
789 | | use super::*; |
790 | | use crate::ring_like::rand::SystemRandom; |
791 | | use crate::ring_like::signature::{EcdsaKeyPair, ECDSA_P256_SHA256_FIXED_SIGNING}; |
792 | | |
793 | | #[cfg(all(feature = "x509-parser", feature = "pem"))] |
794 | | #[test] |
795 | | fn test_subject_public_key_parsing() { |
796 | | for alg in [ |
797 | | &PKCS_ED25519, |
798 | | &PKCS_ECDSA_P256_SHA256, |
799 | | &PKCS_ECDSA_P384_SHA384, |
800 | | #[cfg(feature = "aws_lc_rs")] |
801 | | &PKCS_ECDSA_P521_SHA512, |
802 | | #[cfg(feature = "aws_lc_rs")] |
803 | | &PKCS_RSA_SHA256, |
804 | | ] { |
805 | | let kp = KeyPair::generate_for(alg).expect("keygen"); |
806 | | let pem = kp.public_key_pem(); |
807 | | let der = kp.subject_public_key_info(); |
808 | | |
809 | | let pkd_pem = SubjectPublicKeyInfo::from_pem(&pem).expect("from pem"); |
810 | | assert_eq!(kp.der_bytes(), pkd_pem.der_bytes()); |
811 | | |
812 | | let pkd_der = SubjectPublicKeyInfo::from_der(&der).expect("from der"); |
813 | | assert_eq!(kp.der_bytes(), pkd_der.der_bytes()); |
814 | | } |
815 | | } |
816 | | |
817 | | #[test] |
818 | | fn test_algorithm() { |
819 | | let rng = SystemRandom::new(); |
820 | | let pkcs8 = EcdsaKeyPair::generate_pkcs8(&ECDSA_P256_SHA256_FIXED_SIGNING, &rng).unwrap(); |
821 | | let der = pkcs8.as_ref().to_vec(); |
822 | | |
823 | | let key_pair = KeyPair::try_from(der).unwrap(); |
824 | | assert_eq!(key_pair.algorithm(), &PKCS_ECDSA_P256_SHA256); |
825 | | } |
826 | | } |