1use crate::{EcParameters, Error, Result};
9use core::fmt;
10use der::{
11 Decode, DecodeValue, Encode, EncodeValue, Header, Length, Reader, Sequence, Tag, TagMode,
12 TagNumber, Writer,
13 asn1::{BitStringRef, ContextSpecific, ContextSpecificRef, OctetStringRef},
14};
15
16#[cfg(all(feature = "alloc", feature = "zeroize"))]
17use der::SecretDocument;
18#[cfg(feature = "pem")]
19use der::pem::PemLabel;
20
21const VERSION: u8 = 1;
31
32const EC_PARAMETERS_TAG: TagNumber = TagNumber(0);
34
35const PUBLIC_KEY_TAG: TagNumber = TagNumber(1);
37
38#[derive(Clone)]
61pub struct EcPrivateKey<'a> {
62 pub private_key: &'a [u8],
64
65 pub parameters: Option<EcParameters>,
67
68 pub public_key: Option<&'a [u8]>,
70}
71
72impl<'a> EcPrivateKey<'a> {
73 fn context_specific_parameters(&self) -> Option<ContextSpecificRef<'_, EcParameters>> {
74 self.parameters.as_ref().map(|params| ContextSpecificRef {
75 tag_number: EC_PARAMETERS_TAG,
76 tag_mode: TagMode::Explicit,
77 value: params,
78 })
79 }
80
81 fn context_specific_public_key(
82 &self,
83 ) -> der::Result<Option<ContextSpecific<BitStringRef<'a>>>> {
84 self.public_key
85 .map(|pk| {
86 BitStringRef::from_bytes(pk).map(|value| ContextSpecific {
87 tag_number: PUBLIC_KEY_TAG,
88 tag_mode: TagMode::Explicit,
89 value,
90 })
91 })
92 .transpose()
93 }
94}
95
96impl<'a> DecodeValue<'a> for EcPrivateKey<'a> {
97 type Error = der::Error;
98
99 fn decode_value<R: Reader<'a>>(reader: &mut R, _header: Header) -> der::Result<Self> {
100 if u8::decode(reader)? != VERSION {
101 return Err(reader.error(Tag::Integer.value_error()));
102 }
103
104 let private_key = <&OctetStringRef>::decode(reader)?.as_bytes();
105 let parameters = reader.context_specific(EC_PARAMETERS_TAG, TagMode::Explicit)?;
106 let public_key = reader
107 .context_specific::<BitStringRef<'_>>(PUBLIC_KEY_TAG, TagMode::Explicit)?
108 .map(|bs| bs.as_bytes().ok_or_else(|| Tag::BitString.value_error()))
109 .transpose()?;
110
111 Ok(EcPrivateKey {
112 private_key,
113 parameters,
114 public_key,
115 })
116 }
117}
118
119impl EncodeValue for EcPrivateKey<'_> {
120 fn value_len(&self) -> der::Result<Length> {
121 VERSION.encoded_len()?
122 + OctetStringRef::new(self.private_key)?.encoded_len()?
123 + self.context_specific_parameters().encoded_len()?
124 + self.context_specific_public_key()?.encoded_len()?
125 }
126
127 fn encode_value(&self, writer: &mut impl Writer) -> der::Result<()> {
128 VERSION.encode(writer)?;
129 OctetStringRef::new(self.private_key)?.encode(writer)?;
130 self.context_specific_parameters().encode(writer)?;
131 self.context_specific_public_key()?.encode(writer)?;
132 Ok(())
133 }
134}
135
136impl<'a> Sequence<'a> for EcPrivateKey<'a> {}
137
138impl<'a> TryFrom<&'a [u8]> for EcPrivateKey<'a> {
139 type Error = Error;
140
141 fn try_from(bytes: &'a [u8]) -> Result<EcPrivateKey<'a>> {
142 Ok(Self::from_der(bytes)?)
143 }
144}
145
146impl fmt::Debug for EcPrivateKey<'_> {
147 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
148 f.debug_struct("EcPrivateKey")
149 .field("parameters", &self.parameters)
150 .field("public_key", &self.public_key)
151 .finish_non_exhaustive()
152 }
153}
154
155#[cfg(feature = "alloc")]
156impl TryFrom<EcPrivateKey<'_>> for SecretDocument {
157 type Error = Error;
158
159 fn try_from(private_key: EcPrivateKey<'_>) -> Result<Self> {
160 SecretDocument::try_from(&private_key)
161 }
162}
163
164#[cfg(feature = "alloc")]
165impl TryFrom<&EcPrivateKey<'_>> for SecretDocument {
166 type Error = Error;
167
168 fn try_from(private_key: &EcPrivateKey<'_>) -> Result<Self> {
169 Ok(Self::encode_msg(private_key)?)
170 }
171}
172
173#[cfg(feature = "pem")]
174impl PemLabel for EcPrivateKey<'_> {
175 const PEM_LABEL: &'static str = "EC PRIVATE KEY";
176}