Skip to content

Commit d1fa230

Browse files
committed
elliptic-curve: include curve OID in SEC1 private keys
The OID identifies the particular elliptic curve the key is for. Without it, OpenSSL can't parse these keys. See #1706.
1 parent 9bf215e commit d1fa230

File tree

2 files changed

+31
-13
lines changed

2 files changed

+31
-13
lines changed

Diff for: elliptic-curve/src/secret_key.rs

+15-9
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ use {
2929
sec1::{EncodedPoint, ModulusSize, ValidatePublicKey},
3030
FieldBytesSize,
3131
},
32-
sec1::der,
32+
sec1::der::{self, oid::AssociatedOid},
3333
};
3434

3535
#[cfg(all(feature = "alloc", feature = "arithmetic", feature = "sec1"))]
@@ -184,7 +184,7 @@ where
184184
#[cfg(feature = "sec1")]
185185
pub fn from_sec1_der(der_bytes: &[u8]) -> Result<Self>
186186
where
187-
C: Curve + ValidatePublicKey,
187+
C: AssociatedOid + Curve + ValidatePublicKey,
188188
FieldBytesSize<C>: ModulusSize,
189189
{
190190
sec1::EcPrivateKey::try_from(der_bytes)?
@@ -196,17 +196,18 @@ where
196196
#[cfg(all(feature = "alloc", feature = "arithmetic", feature = "sec1"))]
197197
pub fn to_sec1_der(&self) -> der::Result<Zeroizing<Vec<u8>>>
198198
where
199-
C: CurveArithmetic,
199+
C: AssociatedOid + CurveArithmetic,
200200
AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
201201
FieldBytesSize<C>: ModulusSize,
202202
{
203203
let private_key_bytes = Zeroizing::new(self.to_bytes());
204204
let public_key_bytes = self.public_key().to_encoded_point(false);
205+
let parameters = sec1::EcParameters::NamedCurve(C::OID);
205206

206207
let ec_private_key = Zeroizing::new(
207208
sec1::EcPrivateKey {
208209
private_key: &private_key_bytes,
209-
parameters: None,
210+
parameters: Some(parameters),
210211
public_key: Some(public_key_bytes.as_bytes()),
211212
}
212213
.to_der()?,
@@ -225,7 +226,7 @@ where
225226
#[cfg(feature = "pem")]
226227
pub fn from_sec1_pem(s: &str) -> Result<Self>
227228
where
228-
C: Curve + ValidatePublicKey,
229+
C: AssociatedOid + Curve + ValidatePublicKey,
229230
FieldBytesSize<C>: ModulusSize,
230231
{
231232
let (label, der_bytes) = pem::decode_vec(s.as_bytes()).map_err(|_| Error)?;
@@ -244,7 +245,7 @@ where
244245
#[cfg(feature = "pem")]
245246
pub fn to_sec1_pem(&self, line_ending: pem::LineEnding) -> Result<Zeroizing<String>>
246247
where
247-
C: CurveArithmetic,
248+
C: AssociatedOid + CurveArithmetic,
248249
AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
249250
FieldBytesSize<C>: ModulusSize,
250251
{
@@ -344,16 +345,21 @@ where
344345
#[cfg(feature = "sec1")]
345346
impl<C> TryFrom<sec1::EcPrivateKey<'_>> for SecretKey<C>
346347
where
347-
C: Curve + ValidatePublicKey,
348+
C: AssociatedOid + Curve + ValidatePublicKey,
348349
FieldBytesSize<C>: ModulusSize,
349350
{
350351
type Error = der::Error;
351352

352353
fn try_from(sec1_private_key: sec1::EcPrivateKey<'_>) -> der::Result<Self> {
354+
if let Some(sec1::EcParameters::NamedCurve(curve_oid)) = sec1_private_key.parameters {
355+
if C::OID != curve_oid {
356+
return Err(der::Tag::ObjectIdentifier.value_error());
357+
}
358+
}
359+
353360
let secret_key = Self::from_slice(sec1_private_key.private_key)
354-
.map_err(|_| der::Tag::Sequence.value_error())?;
361+
.map_err(|_| der::Tag::OctetString.value_error())?;
355362

356-
// TODO(tarcieri): validate `sec1_private_key.params`?
357363
if let Some(pk_bytes) = sec1_private_key.public_key {
358364
let pk = EncodedPoint::<C>::from_bytes(pk_bytes)
359365
.map_err(|_| der::Tag::BitString.value_error())?;

Diff for: elliptic-curve/src/secret_key/pkcs8.rs

+16-4
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,10 @@ use {
1717
AffinePoint, CurveArithmetic,
1818
},
1919
pkcs8::{
20-
der::{self, asn1::OctetStringRef},
20+
der::{self, asn1::OctetStringRef, Encode},
2121
EncodePrivateKey,
2222
},
23+
zeroize::Zeroizing,
2324
};
2425

2526
// Imports for actual PEM support
@@ -54,8 +55,7 @@ where
5455
.algorithm
5556
.assert_oids(ALGORITHM_OID, C::OID)?;
5657

57-
let ec_private_key = EcPrivateKey::from_der(private_key_info.private_key.as_bytes())?;
58-
Ok(Self::try_from(ec_private_key)?)
58+
Ok(EcPrivateKey::from_der(private_key_info.private_key.as_bytes())?.try_into()?)
5959
}
6060
}
6161

@@ -72,7 +72,19 @@ where
7272
parameters: Some((&C::OID).into()),
7373
};
7474

75-
let ec_private_key = self.to_sec1_der()?;
75+
let private_key_bytes = Zeroizing::new(self.to_bytes());
76+
let public_key_bytes = self.public_key().to_encoded_point(false);
77+
78+
// TODO(tarcieri): unify with `to_sec1_der()` by building an owned `EcPrivateKey`
79+
let ec_private_key = Zeroizing::new(
80+
EcPrivateKey {
81+
private_key: &private_key_bytes,
82+
parameters: None,
83+
public_key: Some(public_key_bytes.as_bytes()),
84+
}
85+
.to_der()?,
86+
);
87+
7688
let pkcs8_key = pkcs8::PrivateKeyInfoRef::new(
7789
algorithm_identifier,
7890
OctetStringRef::new(&ec_private_key)?,

0 commit comments

Comments
 (0)