/rust/registry/src/index.crates.io-1949cf8c6b5b557f/sec1-0.7.3/src/private_key.rs
Line | Count | Source |
1 | | //! SEC1 elliptic curve private key support. |
2 | | //! |
3 | | //! Support for ASN.1 DER-encoded elliptic curve private keys as described in |
4 | | //! SEC1: Elliptic Curve Cryptography (Version 2.0) Appendix C.4 (p.108): |
5 | | //! |
6 | | //! <https://www.secg.org/sec1-v2.pdf> |
7 | | |
8 | | use crate::{EcParameters, Error, Result}; |
9 | | use core::fmt; |
10 | | use der::{ |
11 | | asn1::{BitStringRef, ContextSpecific, ContextSpecificRef, OctetStringRef}, |
12 | | Decode, DecodeValue, Encode, EncodeValue, Header, Length, Reader, Sequence, Tag, TagMode, |
13 | | TagNumber, Writer, |
14 | | }; |
15 | | |
16 | | #[cfg(all(feature = "alloc", feature = "zeroize"))] |
17 | | use der::SecretDocument; |
18 | | |
19 | | #[cfg(feature = "pem")] |
20 | | use der::pem::PemLabel; |
21 | | |
22 | | /// `ECPrivateKey` version. |
23 | | /// |
24 | | /// From [RFC5913 Section 3]: |
25 | | /// > version specifies the syntax version number of the elliptic curve |
26 | | /// > private key structure. For this version of the document, it SHALL |
27 | | /// > be set to ecPrivkeyVer1, which is of type INTEGER and whose value |
28 | | /// > is one (1). |
29 | | /// |
30 | | /// [RFC5915 Section 3]: https://datatracker.ietf.org/doc/html/rfc5915#section-3 |
31 | | const VERSION: u8 = 1; |
32 | | |
33 | | /// Context-specific tag number for the elliptic curve parameters. |
34 | | const EC_PARAMETERS_TAG: TagNumber = TagNumber::new(0); |
35 | | |
36 | | /// Context-specific tag number for the public key. |
37 | | const PUBLIC_KEY_TAG: TagNumber = TagNumber::new(1); |
38 | | |
39 | | /// SEC1 elliptic curve private key. |
40 | | /// |
41 | | /// Described in [SEC1: Elliptic Curve Cryptography (Version 2.0)] |
42 | | /// Appendix C.4 (p.108) and also [RFC5915 Section 3]: |
43 | | /// |
44 | | /// ```text |
45 | | /// ECPrivateKey ::= SEQUENCE { |
46 | | /// version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1), |
47 | | /// privateKey OCTET STRING, |
48 | | /// parameters [0] ECParameters {{ NamedCurve }} OPTIONAL, |
49 | | /// publicKey [1] BIT STRING OPTIONAL |
50 | | /// } |
51 | | /// ``` |
52 | | /// |
53 | | /// When encoded as PEM (text), keys in this format begin with the following: |
54 | | /// |
55 | | /// ```text |
56 | | /// -----BEGIN EC PRIVATE KEY----- |
57 | | /// ``` |
58 | | /// |
59 | | /// [SEC1: Elliptic Curve Cryptography (Version 2.0)]: https://www.secg.org/sec1-v2.pdf |
60 | | /// [RFC5915 Section 3]: https://datatracker.ietf.org/doc/html/rfc5915#section-3 |
61 | | #[derive(Clone)] |
62 | | pub struct EcPrivateKey<'a> { |
63 | | /// Private key data. |
64 | | pub private_key: &'a [u8], |
65 | | |
66 | | /// Elliptic curve parameters. |
67 | | pub parameters: Option<EcParameters>, |
68 | | |
69 | | /// Public key data, optionally available if version is V2. |
70 | | pub public_key: Option<&'a [u8]>, |
71 | | } |
72 | | |
73 | | impl<'a> EcPrivateKey<'a> { |
74 | 0 | fn context_specific_parameters(&self) -> Option<ContextSpecificRef<'_, EcParameters>> { |
75 | 0 | self.parameters.as_ref().map(|params| ContextSpecificRef { |
76 | | tag_number: EC_PARAMETERS_TAG, |
77 | 0 | tag_mode: TagMode::Explicit, |
78 | 0 | value: params, |
79 | 0 | }) |
80 | 0 | } |
81 | | |
82 | 0 | fn context_specific_public_key( |
83 | 0 | &self, |
84 | 0 | ) -> der::Result<Option<ContextSpecific<BitStringRef<'a>>>> { |
85 | 0 | self.public_key |
86 | 0 | .map(|pk| { |
87 | 0 | BitStringRef::from_bytes(pk).map(|value| ContextSpecific { |
88 | | tag_number: PUBLIC_KEY_TAG, |
89 | 0 | tag_mode: TagMode::Explicit, |
90 | 0 | value, |
91 | 0 | }) |
92 | 0 | }) |
93 | 0 | .transpose() |
94 | 0 | } |
95 | | } |
96 | | |
97 | | impl<'a> DecodeValue<'a> for EcPrivateKey<'a> { |
98 | 0 | fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> der::Result<Self> { |
99 | 0 | reader.read_nested(header.length, |reader| { |
100 | 0 | if u8::decode(reader)? != VERSION { |
101 | 0 | return Err(der::Tag::Integer.value_error()); |
102 | 0 | } |
103 | | |
104 | 0 | let private_key = OctetStringRef::decode(reader)?.as_bytes(); |
105 | 0 | let parameters = reader.context_specific(EC_PARAMETERS_TAG, TagMode::Explicit)?; |
106 | 0 | let public_key = reader |
107 | 0 | .context_specific::<BitStringRef<'_>>(PUBLIC_KEY_TAG, TagMode::Explicit)? |
108 | 0 | .map(|bs| bs.as_bytes().ok_or_else(|| Tag::BitString.value_error())) |
109 | 0 | .transpose()?; |
110 | | |
111 | 0 | Ok(EcPrivateKey { |
112 | 0 | private_key, |
113 | 0 | parameters, |
114 | 0 | public_key, |
115 | 0 | }) |
116 | 0 | }) |
117 | 0 | } |
118 | | } |
119 | | |
120 | | impl EncodeValue for EcPrivateKey<'_> { |
121 | 0 | fn value_len(&self) -> der::Result<Length> { |
122 | 0 | VERSION.encoded_len()? |
123 | 0 | + OctetStringRef::new(self.private_key)?.encoded_len()? |
124 | 0 | + self.context_specific_parameters().encoded_len()? |
125 | 0 | + self.context_specific_public_key()?.encoded_len()? |
126 | 0 | } |
127 | | |
128 | 0 | fn encode_value(&self, writer: &mut impl Writer) -> der::Result<()> { |
129 | 0 | VERSION.encode(writer)?; |
130 | 0 | OctetStringRef::new(self.private_key)?.encode(writer)?; |
131 | 0 | self.context_specific_parameters().encode(writer)?; |
132 | 0 | self.context_specific_public_key()?.encode(writer)?; |
133 | 0 | Ok(()) |
134 | 0 | } |
135 | | } |
136 | | |
137 | | impl<'a> Sequence<'a> for EcPrivateKey<'a> {} |
138 | | |
139 | | impl<'a> TryFrom<&'a [u8]> for EcPrivateKey<'a> { |
140 | | type Error = Error; |
141 | | |
142 | 0 | fn try_from(bytes: &'a [u8]) -> Result<EcPrivateKey<'a>> { |
143 | 0 | Ok(Self::from_der(bytes)?) |
144 | 0 | } |
145 | | } |
146 | | |
147 | | impl<'a> fmt::Debug for EcPrivateKey<'a> { |
148 | 0 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
149 | 0 | f.debug_struct("EcPrivateKey") |
150 | 0 | .field("parameters", &self.parameters) |
151 | 0 | .field("public_key", &self.public_key) |
152 | 0 | .finish_non_exhaustive() |
153 | 0 | } |
154 | | } |
155 | | |
156 | | #[cfg(feature = "alloc")] |
157 | | impl TryFrom<EcPrivateKey<'_>> for SecretDocument { |
158 | | type Error = Error; |
159 | | |
160 | 0 | fn try_from(private_key: EcPrivateKey<'_>) -> Result<Self> { |
161 | 0 | SecretDocument::try_from(&private_key) |
162 | 0 | } |
163 | | } |
164 | | |
165 | | #[cfg(feature = "alloc")] |
166 | | impl TryFrom<&EcPrivateKey<'_>> for SecretDocument { |
167 | | type Error = Error; |
168 | | |
169 | 0 | fn try_from(private_key: &EcPrivateKey<'_>) -> Result<Self> { |
170 | 0 | Ok(Self::encode_msg(private_key)?) |
171 | 0 | } |
172 | | } |
173 | | |
174 | | #[cfg(feature = "pem")] |
175 | | impl PemLabel for EcPrivateKey<'_> { |
176 | | const PEM_LABEL: &'static str = "EC PRIVATE KEY"; |
177 | | } |