Skip to content

Commit acc0093

Browse files
committed
ed25519: check incoming PKCS#8 public key
1 parent 6790fce commit acc0093

3 files changed

Lines changed: 46 additions & 4 deletions

File tree

graviola/src/error.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ pub enum KeyFormatError {
3939
UnsupportedPkcs8Version,
4040
MismatchedPkcs8Algorithm,
4141
MismatchedPkcs8Parameters,
42+
MismatchedPkcs8PublicKey,
4243
MismatchedSec1Curve,
4344
MismatchedSec1PublicKey,
4445
MismatchedSpkiAlgorithm,
@@ -56,6 +57,7 @@ impl core::fmt::Display for KeyFormatError {
5657
Self::UnsupportedPkcs8Version => write!(f, "unsupported PKCS#8 version"),
5758
Self::MismatchedPkcs8Algorithm => write!(f, "mismatched PKCS#8 algorithm"),
5859
Self::MismatchedPkcs8Parameters => write!(f, "mismatched PKCS#8 parameters"),
60+
Self::MismatchedPkcs8PublicKey => write!(f, "mismatched PKCS#8 public key"),
5961
Self::MismatchedSec1Curve => write!(f, "mismatched SEC1 curve"),
6062
Self::MismatchedSec1PublicKey => write!(f, "mismatched SEC1 public key"),
6163
Self::MismatchedSpkiAlgorithm => write!(f, "mismatched SPKI algorithm"),

graviola/src/high/ed25519.rs

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,9 +92,20 @@ impl Ed25519SigningKey {
9292
pub fn from_pkcs8_der(bytes: &[u8]) -> Result<Self, Error> {
9393
let _entry = Entry::new_secret();
9494

95-
pkcs8::Key::decode(bytes, &asn1::oid::id_ed25519, None)
96-
.and_then(|k| asn1::OctetString::from_bytes(k.private_key()).map_err(Error::Asn1Error))
97-
.and_then(|pk| Self::from_bytes(pk.as_octets()))
95+
let p8 = pkcs8::Key::decode(bytes, &asn1::oid::id_ed25519, None)?;
96+
97+
let key = asn1::OctetString::from_bytes(p8.private_key())
98+
.map_err(Error::Asn1Error)
99+
.and_then(|pk| Self::from_bytes(pk.as_octets()))?;
100+
101+
if let Some(alleged_pub_key) = p8.public_key() {
102+
let actual_pub_key = key.public_key().as_bytes();
103+
if alleged_pub_key != actual_pub_key {
104+
return Err(KeyFormatError::MismatchedPkcs8PublicKey.into());
105+
}
106+
}
107+
108+
Ok(key)
98109
}
99110

100111
/// Encode this private key in PKCS#8 DER format.
@@ -174,4 +185,34 @@ mod tests {
174185
let buf = key.to_pkcs8_der(&mut buf).unwrap();
175186
assert_eq!(bytes, buf);
176187
}
188+
189+
#[test]
190+
fn pkcs8_public_key_wrong() {
191+
let mut bytes = include_bytes!("asn1/testdata/ed25519-p8v2.bin").to_vec();
192+
bytes[52] ^= 0x01;
193+
assert_eq!(
194+
Ed25519SigningKey::from_pkcs8_der(&bytes).err(),
195+
Some(KeyFormatError::MismatchedPkcs8PublicKey.into())
196+
);
197+
}
198+
199+
#[test]
200+
fn spki_wrong_oid() {
201+
Ed25519VerifyingKey::from_spki_der(&[
202+
0x30, 0x2a, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70, 0x03, 0x21, 0x00, 0xdd, 0x2d,
203+
0x67, 0x8b, 0xae, 0x22, 0x2f, 0x3f, 0xb6, 0xe8, 0x27, 0x8f, 0x08, 0xcc, 0x9e, 0x1a,
204+
0x66, 0x33, 0x9c, 0x92, 0x6c, 0x29, 0xac, 0x0a, 0x16, 0xf9, 0x71, 0x7f, 0x5e, 0xe1,
205+
0x8c, 0xd8,
206+
])
207+
.unwrap();
208+
209+
let e = Ed25519VerifyingKey::from_spki_der(&[
210+
0x30, 0x2a, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x64, 0x70, 0x03, 0x21, 0x00, 0xdd, 0x2d,
211+
0x67, 0x8b, 0xae, 0x22, 0x2f, 0x3f, 0xb6, 0xe8, 0x27, 0x8f, 0x08, 0xcc, 0x9e, 0x1a,
212+
0x66, 0x33, 0x9c, 0x92, 0x6c, 0x29, 0xac, 0x0a, 0x16, 0xf9, 0x71, 0x7f, 0x5e, 0xe1,
213+
0x8c, 0xd8,
214+
])
215+
.unwrap_err();
216+
assert_eq!(e, KeyFormatError::MismatchedSpkiAlgorithm.into());
217+
}
177218
}

graviola/src/high/pkcs8.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,6 @@ impl<'a> Key<'a> {
9797
///
9898
/// This can be decoded by the caller as the correct asn1 type (or
9999
/// used raw, depending on the type)
100-
#[cfg_attr(not(test), expect(dead_code))]
101100
pub(crate) fn public_key(&self) -> Option<&'a [u8]> {
102101
self.0.publicKey.inner().as_ref().map(|x| x.as_octets())
103102
}

0 commit comments

Comments
 (0)