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> { context_specific_parameters(&self) -> Option<ContextSpecificRef<'_, EcParameters>>74 fn context_specific_parameters(&self) -> Option<ContextSpecificRef<'_, EcParameters>> { 75 self.parameters.as_ref().map(|params| ContextSpecificRef { 76 tag_number: EC_PARAMETERS_TAG, 77 tag_mode: TagMode::Explicit, 78 value: params, 79 }) 80 } 81 context_specific_public_key( &self, ) -> der::Result<Option<ContextSpecific<BitStringRef<'a>>>>82 fn context_specific_public_key( 83 &self, 84 ) -> der::Result<Option<ContextSpecific<BitStringRef<'a>>>> { 85 self.public_key 86 .map(|pk| { 87 BitStringRef::from_bytes(pk).map(|value| ContextSpecific { 88 tag_number: PUBLIC_KEY_TAG, 89 tag_mode: TagMode::Explicit, 90 value, 91 }) 92 }) 93 .transpose() 94 } 95 } 96 97 impl<'a> DecodeValue<'a> for EcPrivateKey<'a> { decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> der::Result<Self>98 fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> der::Result<Self> { 99 reader.read_nested(header.length, |reader| { 100 if u8::decode(reader)? != VERSION { 101 return Err(der::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 } 119 120 impl EncodeValue for EcPrivateKey<'_> { value_len(&self) -> der::Result<Length>121 fn value_len(&self) -> der::Result<Length> { 122 VERSION.encoded_len()? 123 + OctetStringRef::new(self.private_key)?.encoded_len()? 124 + self.context_specific_parameters().encoded_len()? 125 + self.context_specific_public_key()?.encoded_len()? 126 } 127 encode_value(&self, writer: &mut impl Writer) -> der::Result<()>128 fn encode_value(&self, writer: &mut impl Writer) -> der::Result<()> { 129 VERSION.encode(writer)?; 130 OctetStringRef::new(self.private_key)?.encode(writer)?; 131 self.context_specific_parameters().encode(writer)?; 132 self.context_specific_public_key()?.encode(writer)?; 133 Ok(()) 134 } 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 try_from(bytes: &'a [u8]) -> Result<EcPrivateKey<'a>>142 fn try_from(bytes: &'a [u8]) -> Result<EcPrivateKey<'a>> { 143 Ok(Self::from_der(bytes)?) 144 } 145 } 146 147 impl<'a> fmt::Debug for EcPrivateKey<'a> { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result148 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 149 f.debug_struct("EcPrivateKey") 150 .field("parameters", &self.parameters) 151 .field("public_key", &self.public_key) 152 .finish_non_exhaustive() 153 } 154 } 155 156 #[cfg(feature = "alloc")] 157 impl TryFrom<EcPrivateKey<'_>> for SecretDocument { 158 type Error = Error; 159 try_from(private_key: EcPrivateKey<'_>) -> Result<Self>160 fn try_from(private_key: EcPrivateKey<'_>) -> Result<Self> { 161 SecretDocument::try_from(&private_key) 162 } 163 } 164 165 #[cfg(feature = "alloc")] 166 impl TryFrom<&EcPrivateKey<'_>> for SecretDocument { 167 type Error = Error; 168 try_from(private_key: &EcPrivateKey<'_>) -> Result<Self>169 fn try_from(private_key: &EcPrivateKey<'_>) -> Result<Self> { 170 Ok(Self::encode_msg(private_key)?) 171 } 172 } 173 174 #[cfg(feature = "pem")] 175 impl PemLabel for EcPrivateKey<'_> { 176 const PEM_LABEL: &'static str = "EC PRIVATE KEY"; 177 } 178