1use crate::{oids, AlgorithmIdentifier, AlgorithmIdentifierParameters, EcParameters, EncapsulatedEcPoint};
2
3use picky_asn1::tag::TagPeeker;
4use picky_asn1::wrapper::{
5 BitStringAsn1, ExplicitContextTag0, ExplicitContextTag1, IntegerAsn1, ObjectIdentifierAsn1, OctetStringAsn1,
6 OctetStringAsn1Container, Optional,
7};
8#[cfg(not(feature = "legacy"))]
9use serde::Deserialize;
10use serde::{de, ser, Serialize};
11#[cfg(feature = "zeroize")]
12use zeroize::Zeroize;
13
14use oid::ObjectIdentifier;
15use picky_asn1::bit_string::BitString;
16use picky_asn1::Asn1Type;
17use std::fmt;
18
19pub const PRIVATE_KEY_INFO_VERSION_1: u8 = 0;
22pub const PRIVATE_KEY_INFO_VERSION_2: u8 = 1;
26
27pub type EncapsulatedEcSecret = OctetStringAsn1;
28
29#[derive(Serialize, Debug, Clone, PartialEq, Eq)]
81pub struct PrivateKeyInfo {
82 pub version: u8,
83 pub private_key_algorithm: AlgorithmIdentifier,
84 pub private_key: PrivateKeyValue,
85 pub public_key: Option<ExplicitContextTag1<Optional<BitStringAsn1>>>,
87}
88
89impl PrivateKeyInfo {
90 pub fn new_rsa_encryption(
91 modulus: IntegerAsn1,
92 public_exponent: IntegerAsn1,
93 private_exponent: IntegerAsn1,
94 primes: (IntegerAsn1, IntegerAsn1),
95 exponents: (IntegerAsn1, IntegerAsn1),
96 coefficient: IntegerAsn1,
97 ) -> Self {
98 let private_key = PrivateKeyValue::Rsa(
99 RsaPrivateKey {
100 version: vec![0].into(),
101 modulus,
102 public_exponent,
103 private_exponent,
104 prime_1: primes.0,
105 prime_2: primes.1,
106 exponent_1: exponents.0,
107 exponent_2: exponents.1,
108 coefficient,
109 }
110 .into(),
111 );
112
113 Self {
114 version: PRIVATE_KEY_INFO_VERSION_1,
115 private_key_algorithm: AlgorithmIdentifier::new_rsa_encryption(),
116 private_key,
117 public_key: None,
118 }
119 }
120
121 pub fn new_ec_encryption(
127 curve_oid: ObjectIdentifier,
128 secret: impl Into<OctetStringAsn1>,
129 public_point: Option<BitString>,
130 skip_optional_params: bool,
131 ) -> Self {
132 let curve_oid: ObjectIdentifierAsn1 = curve_oid.into();
133 let secret: OctetStringAsn1 = secret.into();
134 let point: Option<BitStringAsn1> = public_point.map(Into::into);
135
136 let parameters: ExplicitContextTag0<Option<EcParameters>> =
137 (!skip_optional_params).then(|| curve_oid.clone().into()).into();
138 let public_point: ExplicitContextTag1<Option<BitStringAsn1>> = point.into();
139
140 let private_key = PrivateKeyValue::EC(
141 ECPrivateKey {
142 version: vec![1].into(),
143 private_key: secret,
144 parameters: parameters.into(),
145 public_key: public_point.into(),
146 }
147 .into(),
148 );
149
150 Self {
151 version: PRIVATE_KEY_INFO_VERSION_1,
152 private_key_algorithm: AlgorithmIdentifier::new_elliptic_curve(curve_oid.into()),
153 private_key,
154 public_key: None,
155 }
156 }
157
158 pub fn new_ed_encryption(
159 algorithm: ObjectIdentifier,
160 secret: impl Into<OctetStringAsn1>,
161 public_key: Option<BitString>,
162 ) -> Self {
163 let secret: OctetStringAsn1 = secret.into();
164
165 let (version, public_key) = if let Some(public_key) = public_key {
166 (
168 PRIVATE_KEY_INFO_VERSION_2,
169 Some(ExplicitContextTag1(Optional(public_key.into()))),
170 )
171 } else {
172 (PRIVATE_KEY_INFO_VERSION_1, None)
173 };
174
175 Self {
176 version,
177 private_key_algorithm: AlgorithmIdentifier::new_unchecked(algorithm, AlgorithmIdentifierParameters::None),
178 private_key: PrivateKeyValue::ED(secret.into()),
179 public_key,
180 }
181 }
182}
183
184impl<'de> de::Deserialize<'de> for PrivateKeyInfo {
185 fn deserialize<D>(deserializer: D) -> Result<Self, <D as de::Deserializer<'de>>::Error>
186 where
187 D: de::Deserializer<'de>,
188 {
189 struct Visitor;
190
191 impl<'de> de::Visitor<'de> for Visitor {
192 type Value = PrivateKeyInfo;
193
194 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
195 formatter.write_str("a valid DER-encoded PrivateKeyInfo (pkcs8)")
196 }
197
198 fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
199 where
200 A: de::SeqAccess<'de>,
201 {
202 let version = seq_next_element!(seq, PrivateKeyInfo, "version");
203 if version != 0 && version != 1 {
204 return Err(serde_invalid_value!(
205 PrivateKeyInfo,
206 "unsupported version (valid versions: [v1(0), v2(1)])",
207 "a supported PrivateKeyInfo"
208 ));
209 }
210
211 let private_key_algorithm: AlgorithmIdentifier =
212 seq_next_element!(seq, PrivateKeyInfo, "private key algorithm");
213
214 let private_key = if private_key_algorithm.is_a(oids::rsa_encryption()) {
215 PrivateKeyValue::Rsa(seq_next_element!(seq, PrivateKeyInfo, "rsa oid"))
216 } else if matches!(private_key_algorithm.parameters(), AlgorithmIdentifierParameters::Ec(_)) {
217 PrivateKeyValue::EC(seq_next_element!(seq, PrivateKeyInfo, "ec private key"))
218 } else if private_key_algorithm.is_one_of([oids::ed25519(), oids::x25519()]) {
219 PrivateKeyValue::ED(seq_next_element!(seq, PrivateKeyInfo, "curve25519 private key"))
220 } else if private_key_algorithm.is_one_of([oids::ed448(), oids::x448()]) {
221 PrivateKeyValue::ED(seq_next_element!(seq, PrivateKeyInfo, "curve448 private key"))
222 } else {
223 return Err(serde_invalid_value!(
224 PrivateKeyInfo,
225 "unsupported algorithm",
226 "a supported algorithm"
227 ));
228 };
229
230 let mut last_tag = seq.next_element::<TagPeeker>()?;
231
232 if let Some(tag) = &last_tag {
233 if tag.next_tag != ExplicitContextTag1::<BitStringAsn1>::TAG {
234 last_tag = seq.next_element::<TagPeeker>()?;
236 }
237 }
238
239 let public_key = match last_tag {
241 Some(tag) if tag.next_tag == ExplicitContextTag1::<BitStringAsn1>::TAG => {
242 let public_key =
243 seq_next_element!(seq, ExplicitContextTag1<BitStringAsn1>, PrivateKeyInfo, "BitStringAsn1");
244
245 Some(ExplicitContextTag1(Optional(public_key.0)))
246 }
247 _ => None,
248 };
249
250 Ok(PrivateKeyInfo {
251 version,
252 private_key_algorithm,
253 private_key,
254 public_key,
255 })
256 }
257 }
258
259 deserializer.deserialize_seq(Visitor)
260 }
261}
262
263#[derive(Debug, PartialEq, Eq, Clone)]
264pub enum PrivateKeyValue {
265 Rsa(OctetStringAsn1Container<RsaPrivateKey>),
266 EC(OctetStringAsn1Container<ECPrivateKey>),
267 ED(OctetStringAsn1Container<OctetStringAsn1>),
269}
270
271impl ser::Serialize for PrivateKeyValue {
272 fn serialize<S>(&self, serializer: S) -> Result<<S as ser::Serializer>::Ok, <S as ser::Serializer>::Error>
273 where
274 S: ser::Serializer,
275 {
276 match self {
277 PrivateKeyValue::Rsa(rsa) => rsa.serialize(serializer),
278 PrivateKeyValue::EC(ec) => ec.serialize(serializer),
279 PrivateKeyValue::ED(ed) => ed.serialize(serializer),
280 }
281 }
282}
283
284#[cfg(feature = "zeroize")]
285impl Drop for PrivateKeyValue {
286 fn drop(&mut self) {
287 if let PrivateKeyValue::ED(ed) = self {
288 ed.0 .0.zeroize()
289 }
290 }
291}
292
293#[derive(Serialize, Debug, Clone, PartialEq, Eq)]
314#[cfg_attr(not(feature = "legacy"), derive(Deserialize))]
315pub struct RsaPrivateKey {
316 pub version: IntegerAsn1,
317 pub modulus: IntegerAsn1,
318 pub public_exponent: IntegerAsn1,
319 pub private_exponent: IntegerAsn1,
320 pub prime_1: IntegerAsn1,
321 pub prime_2: IntegerAsn1,
322 pub exponent_1: IntegerAsn1,
323 pub exponent_2: IntegerAsn1,
324 pub coefficient: IntegerAsn1,
325}
326
327#[cfg(feature = "zeroize")]
328impl Drop for RsaPrivateKey {
329 fn drop(&mut self) {
330 self.private_exponent.zeroize();
331 }
332}
333
334#[cfg(feature = "legacy")]
335impl<'de> de::Deserialize<'de> for RsaPrivateKey {
336 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
337 where
338 D: de::Deserializer<'de>,
339 {
340 struct Visitor;
341
342 impl<'de> de::Visitor<'de> for Visitor {
343 type Value = RsaPrivateKey;
344
345 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
346 formatter.write_str("struct RSAPrivateKey with 6 or 9 elements")
347 }
348
349 fn visit_seq<V>(self, mut seq: V) -> Result<Self::Value, V::Error>
350 where
351 V: de::SeqAccess<'de>,
352 {
353 let version: IntegerAsn1 = seq.next_element()?.ok_or_else(|| de::Error::invalid_length(0, &self))?;
354 let modulus: IntegerAsn1 = seq.next_element()?.ok_or_else(|| de::Error::invalid_length(1, &self))?;
355 let public_exponent: IntegerAsn1 =
356 seq.next_element()?.ok_or_else(|| de::Error::invalid_length(2, &self))?;
357 let private_exponent: IntegerAsn1 =
358 seq.next_element()?.ok_or_else(|| de::Error::invalid_length(3, &self))?;
359 let prime_1: IntegerAsn1 = seq.next_element()?.ok_or_else(|| de::Error::invalid_length(4, &self))?;
360 let prime_2: IntegerAsn1 = seq.next_element()?.ok_or_else(|| de::Error::invalid_length(5, &self))?;
361
362 let (exponent_1, exponent_2, coefficient) = if let Some(exponent_1) = seq.next_element()? {
363 let exponent_2 = seq.next_element()?.ok_or_else(|| de::Error::invalid_length(7, &self))?;
364 let coefficient = seq.next_element()?.ok_or_else(|| de::Error::invalid_length(8, &self))?;
365 (exponent_1, exponent_2, coefficient)
366 } else {
367 use num_bigint_dig::{BigUint, ModInverse};
368
369 let private_exponent = BigUint::from_bytes_be(private_exponent.as_unsigned_bytes_be());
371 let prime_1 = BigUint::from_bytes_be(prime_1.as_unsigned_bytes_be());
372 let prime_2 = BigUint::from_bytes_be(prime_2.as_unsigned_bytes_be());
373
374 let exponent_1 = &private_exponent % (&prime_1 - 1u8);
375 let exponent_2 = &private_exponent % (&prime_2 - 1u8);
376
377 let coefficient = prime_2
378 .mod_inverse(prime_1)
379 .ok_or_else(|| {
380 de::Error::invalid_value(
381 de::Unexpected::Other("[RSAPrivateKey] no modular inverse for prime 1"),
382 &"an invertible prime 1 value",
383 )
384 })?
385 .to_biguint()
386 .ok_or_else(|| {
387 de::Error::invalid_value(
388 de::Unexpected::Other("[RSAPrivateKey] BigUint conversion failed"),
389 &"a valid prime 1 value",
390 )
391 })?;
392
393 let exponent_1 = IntegerAsn1::from_bytes_be_unsigned(exponent_1.to_bytes_be());
395 let exponent_2 = IntegerAsn1::from_bytes_be_unsigned(exponent_2.to_bytes_be());
396 let coefficient = IntegerAsn1::from_bytes_be_unsigned(coefficient.to_bytes_be());
397
398 (exponent_1, exponent_2, coefficient)
399 };
400
401 Ok(RsaPrivateKey {
402 version,
403 modulus,
404 public_exponent,
405 private_exponent,
406 prime_1,
407 prime_2,
408 exponent_1,
409 exponent_2,
410 coefficient,
411 })
412 }
413 }
414
415 deserializer.deserialize_seq(Visitor)
416 }
417}
418
419impl RsaPrivateKey {
420 #[deprecated(note = "field is now public")]
421 pub fn modulus(&self) -> &IntegerAsn1 {
422 &self.modulus
423 }
424
425 #[deprecated(note = "field is now public")]
426 pub fn public_exponent(&self) -> &IntegerAsn1 {
427 &self.public_exponent
428 }
429
430 #[deprecated(note = "field is now public")]
431 pub fn private_exponent(&self) -> &IntegerAsn1 {
432 &self.private_exponent
433 }
434
435 #[deprecated(note = "field is now public")]
436 pub fn prime_1(&self) -> &IntegerAsn1 {
437 &self.prime_1
438 }
439
440 #[deprecated(note = "field is now public")]
441 pub fn prime_2(&self) -> &IntegerAsn1 {
442 &self.prime_2
443 }
444
445 #[deprecated(note = "field is now public")]
446 pub fn primes(&self) -> (&IntegerAsn1, &IntegerAsn1) {
447 (&self.prime_1, &self.prime_2)
448 }
449
450 #[deprecated(note = "field is now public")]
451 pub fn exponent_1(&self) -> &IntegerAsn1 {
452 &self.exponent_1
453 }
454
455 #[deprecated(note = "field is now public")]
456 pub fn exponent_2(&self) -> &IntegerAsn1 {
457 &self.exponent_2
458 }
459
460 #[deprecated(note = "field is now public")]
461 pub fn exponents(&self) -> (&IntegerAsn1, &IntegerAsn1) {
462 (&self.exponent_1, &self.exponent_2)
463 }
464
465 #[deprecated(note = "field is now public")]
466 pub fn coefficient(&self) -> &IntegerAsn1 {
467 &self.coefficient
468 }
469
470 #[deprecated(note = "field is now public")]
471 pub fn into_public_components(mut self) -> (IntegerAsn1, IntegerAsn1) {
472 (
473 std::mem::take(&mut self.modulus),
474 std::mem::take(&mut self.public_exponent),
475 )
476 }
477}
478
479#[derive(Serialize, Debug, Clone, PartialEq, Eq)]
492pub struct ECPrivateKey {
493 pub version: IntegerAsn1,
494 pub private_key: EncapsulatedEcSecret,
495 #[serde(skip_serializing_if = "Optional::is_default")]
496 pub parameters: Optional<ExplicitContextTag0<Option<EcParameters>>>,
497 #[serde(skip_serializing_if = "Optional::is_default")]
498 pub public_key: Optional<ExplicitContextTag1<Option<EncapsulatedEcPoint>>>,
499}
500
501impl<'de> serde::Deserialize<'de> for ECPrivateKey {
502 fn deserialize<D>(deserializer: D) -> Result<Self, <D as de::Deserializer<'de>>::Error>
503 where
504 D: de::Deserializer<'de>,
505 {
506 struct Visitor;
507
508 impl<'de> de::Visitor<'de> for Visitor {
509 type Value = ECPrivateKey;
510
511 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
512 formatter.write_str("a valid DER-encoded PrivateKeyInfo (pkcs8)")
513 }
514
515 fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
516 where
517 A: de::SeqAccess<'de>,
518 {
519 let version: IntegerAsn1 = seq_next_element!(seq, IntegerAsn1, "IntegerAsn1");
520 if version.0 != [1] {
521 return Err(serde_invalid_value!(
522 ECPrivateKey,
523 "ECPrivateKey's version is not 1",
524 "ECPrivateKey's version equals to 1"
525 ));
526 }
527
528 let private_key = seq_next_element!(seq, OctetStringAsn1, "OctetStringAsn1");
529
530 let mut ec_private_key = ECPrivateKey {
531 version,
532 private_key,
533 parameters: Optional::default(),
534 public_key: Optional::default(),
535 };
536
537 let mut last_tag = seq.next_element::<TagPeeker>()?;
538
539 if let Some(tag) = &last_tag {
540 if tag.next_tag == ExplicitContextTag0::<EcParameters>::TAG {
541 let parameters =
542 seq_next_element!(seq, ExplicitContextTag0<EcParameters>, ECPrivateKey, "EcParameters");
543
544 ec_private_key.parameters = Optional(ExplicitContextTag0(Some(parameters.0)));
545
546 last_tag = seq.next_element::<TagPeeker>()?;
548 }
549 }
550
551 if let Some(tag) = last_tag {
552 if tag.next_tag == ExplicitContextTag1::<BitStringAsn1>::TAG {
553 let public_key =
554 seq_next_element!(seq, ExplicitContextTag1<BitStringAsn1>, ECPrivateKey, "BitStringAsn1");
555
556 ec_private_key.public_key = Optional(ExplicitContextTag1(Some(public_key.0)));
557 }
558 }
559
560 Ok(ec_private_key)
561 }
562 }
563
564 deserializer.deserialize_seq(Visitor)
565 }
566}
567
568#[cfg(feature = "zeroize")]
569impl Drop for ECPrivateKey {
570 fn drop(&mut self) {
571 self.private_key.zeroize();
572 }
573}
574
575#[cfg(test)]
576mod tests {
577 use super::*;
578 use base64::{engine::general_purpose, Engine as _};
579 use picky_asn1::bit_string::BitString;
580
581 #[test]
582 fn pkcs_8_private_key() {
583 let encoded = general_purpose::STANDARD
584 .decode(
585 "MIIBVgIBADANBgkqhkiG9w0BAQEFAASCAUAwggE8AgEAAkEAq7BFUpkGp3+LQmlQ\
586 Yx2eqzDV+xeG8kx/sQFV18S5JhzGeIJNA72wSeukEPojtqUyX2J0CciPBh7eqclQ\
587 2zpAswIDAQABAkAgisq4+zRdrzkwH1ITV1vpytnkO/NiHcnePQiOW0VUybPyHoGM\
588 /jf75C5xET7ZQpBe5kx5VHsPZj0CBb3b+wSRAiEA2mPWCBytosIU/ODRfq6EiV04\
589 lt6waE7I2uSPqIC20LcCIQDJQYIHQII+3YaPqyhGgqMexuuuGx+lDKD6/Fu/JwPb\
590 5QIhAKthiYcYKlL9h8bjDsQhZDUACPasjzdsDEdq8inDyLOFAiEAmCr/tZwA3qeA\
591 ZoBzI10DGPIuoKXBd3nk/eBxPkaxlEECIQCNymjsoI7GldtujVnr1qT+3yedLfHK\
592 srDVjIT3LsvTqw==",
593 )
594 .expect("invalid base64");
595
596 let modulus = IntegerAsn1::from(encoded[35..100].to_vec());
597 let public_exponent = IntegerAsn1::from(encoded[102..105].to_vec());
598 let private_exponent = IntegerAsn1::from(encoded[107..171].to_vec());
599 let prime_1 = IntegerAsn1::from(encoded[173..206].to_vec());
600 let prime_2 = IntegerAsn1::from(encoded[208..241].to_vec());
601 let exponent_1 = IntegerAsn1::from(encoded[243..276].to_vec());
602 let exponent_2 = IntegerAsn1::from(encoded[278..311].to_vec());
603 let coefficient = IntegerAsn1::from(encoded[313..346].to_vec());
604
605 let private_key = PrivateKeyInfo::new_rsa_encryption(
606 modulus,
607 public_exponent,
608 private_exponent,
609 (prime_1, prime_2),
610 (exponent_1, exponent_2),
611 coefficient,
612 );
613 check_serde!(private_key: PrivateKeyInfo in encoded);
614 }
615
616 #[test]
617 #[cfg(feature = "legacy")]
618 fn old_broken_key_legacy_support() {
619 let encoded = general_purpose::STANDARD
624 .decode(
625 "MIIDMAIBADANBgkqhkiG9w0BAQEFAASCAxowggMWAgEAAoIBAOB9jOJvCkMHOc98Q\
626 GPFikxAvBKANkme5f/nNuNnEnbefoKDFkS6ElfqASAAkIHxUREnRvBTTa6b+qba/0\
627 DhBuXsYGCl8VF0pUE4JGujv1HIi5aRCar0WmY66s7DJ4uR3Nk9Jy0WeRiH4yyzEIG\
628 8+6QDu4d/U6slWTmE8eZtQEE7rz4FGpQU9OhrGM3xJOIIbLX/xU2SFt83Xs3JREEt\
629 bfrXQpSxAHmtwvlBKpeZacrcobm6eQKsoI2MIg3LFvoHs0+40dadm14ngpgwx4qqk\
630 bG34jvWH13OhHRweFGNkQpcg99rlzZYkCM13e9EcmirQ9XYHuB5pHS31eznolZKbx\
631 cCAwEAAQKCAQCrPFlopxaGxk48jCR5dkbln0NWQWInigMazf06PHcDIPgTCXbE+cH\
632 gOWieRo/z7mTN1s3vpztMA0KQX9/wVzVx0Ho7fpiyb21WcEKnsIHRGk4PjZZ4Rmdm\
633 L27IRGg3uA1jz5fAdrHsGksY34Wp0MOJ+ibjViY2GAkVLOlvwMoQds6eNIGO88T5O\
634 fcmvutjK43ObU1vgx2ptTaLNAVczEE5VHqcLx4GZPv6k71afOQfIDQerIpsGb4gvr\
635 1JdwYKb4z02z2SaNIA3Vly0q5s4r8uU36eg9z65utu93M7zI7f8/MX2byZ2Jz4b3T\
636 nH10FURmbPoNQH/O2T0TbtT4M1y0xAoGA72JW0IcFxze7j7PPaP6cQN1IXvFDZUFF\
637 dZHqFI8+4VPcv3EKTs+iQflM7pqtRuEWtwonIn3f7CGOx317uKwpVsZvfnDhXCUPJ\
638 Q3pns7KgaROGXyruFFQ9gl6XsXGK02Wop9nX0/iRK3ruwZ4uJwDioEYcvGw+ocqAc\
639 yOdodNnpUCgYDwEo/sPJNaPOzc7fpaQr2PUUJ3ksL0ncGRO2h1JGYgDtWe5u1srSI\
640 DlpM2NdYSZyT04ebOF2SqNUBwY3LB1tPOFnjYwCutp4c75OYhOor7TodZHlzt3GeQ\
641 ntUw6XbHX0ohTgs4u2NXwOTq5yKeW4VYzuevN5ksF8GoW2noalpn+w==",
642 )
643 .unwrap();
644
645 picky_asn1_der::from_bytes::<PrivateKeyInfo>(&encoded).unwrap();
646 }
647
648 #[test]
649 fn decode_ec_key() {
650 let decoded = general_purpose::STANDARD
651 .decode(
652 "\
653 MIHcAgEBBEIBhqphIGu2PmlcEb6xADhhSCpgPUulB0s4L2qOgolRgaBx4fNgINFE\
654 mBsSyHJncsWG8WFEuUzAYy/YKz2lP0Qx6Z2gBwYFK4EEACOhgYkDgYYABABwBevJ\
655 w/+Xh6I98ruzoTX3MNTsbgnc+glenJRCbEJkjbJrObFhbfgqP52r1lAy2RxuShGi\
656 NYJJzNPT6vR1abS32QFtvTH7YbYa6OWk9dtGNY/cYxgx1nQyhUuofdW7qbbfu/Ww\
657 TP2oFsPXRAavZCh4AbWUn8bAHmzNRyuJonQBKlQlVQ==",
658 )
659 .unwrap();
660
661 let ec_key = ECPrivateKey {
662 version: IntegerAsn1([1].into()),
663 private_key: OctetStringAsn1::from(decoded[8..74].to_vec()),
664 parameters: ExplicitContextTag0(Some(EcParameters::NamedCurve(oids::secp521r1().into()))).into(),
665 public_key: Optional(ExplicitContextTag1(Some(
666 BitString::with_bytes(decoded[90..].to_vec()).into(),
667 ))),
668 };
669
670 check_serde!(ec_key: ECPrivateKey in decoded);
671 }
672
673 #[test]
674 fn decode_pkcs8_ec_key() {
675 let decoded = general_purpose::STANDARD.decode("MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgKZqrmOg/cDZ4tPCn\
676 4LROs145nxx+ssufvflL8cROxFmhRANCAARmU90fCSTsncefY7hVeKw1WIg/YQmT\
677 4DGJ7nJPZ+WXAd/xxp4c0bHGlIOju/U95ITPN9dAmro7OUTDJpz+rzGW").unwrap();
678 let expected_pkcs8_ec_key = PrivateKeyInfo {
679 version: 0,
680 private_key_algorithm: AlgorithmIdentifier::new_elliptic_curve(EcParameters::NamedCurve(
681 oids::secp256r1().into(),
682 )),
683 private_key: PrivateKeyValue::EC(OctetStringAsn1Container(ECPrivateKey {
684 version: IntegerAsn1([1].into()),
685 private_key: OctetStringAsn1(decoded[36..68].to_vec()),
686 parameters: Optional(Default::default()),
687 public_key: Optional(ExplicitContextTag1(Some(
688 BitString::with_bytes(decoded[73..].to_vec()).into(),
689 ))),
690 })),
691 public_key: None,
692 };
693
694 check_serde!(expected_pkcs8_ec_key: PrivateKeyInfo in decoded);
695 }
696}