Skip to content

ed448_goldilocks::SigningKey::from_pkcs8_pem fails due to slice length mismatch (in 0.14.0-pre.2) #1326

@LukasKalbertodt

Description

@LukasKalbertodt

I tried using version of 0.14.0-pre.2 of ed448_goldilocks and encountered a problem that I'm pretty sure is a bug in the library:

const PRIVATE_KEY: &str = "-----BEGIN PRIVATE KEY-----
MEcCAQAwBQYDK2VxBDsEOYrsF28Jlv/NB2SCjTz0Ax578DThtcGskl01aPFyjIsQ
yx0O34c/sstZ3SeqFbpP62izrpcSrMDXJA==
-----END PRIVATE KEY-----
";

use ed448_goldilocks::{SigningKey, pkcs8::DecodePrivateKey};

SigningKey::from_pkcs8_pem(PRIVATE_KEY)

This returns an Err, despite the key being correct. I think the bug is here:

#[cfg(feature = "pkcs8")]
impl TryFrom<pkcs8::PrivateKeyInfoRef<'_>> for KeypairBytes {
type Error = pkcs8::Error;
fn try_from(value: pkcs8::PrivateKeyInfoRef<'_>) -> Result<Self, Self::Error> {
if value.algorithm.oid != super::ALGORITHM_OID {
return Err(pkcs8::Error::KeyMalformed);
}
if value.private_key.as_bytes().len() != SECRET_KEY_LENGTH {
return Err(pkcs8::Error::KeyMalformed);
}
let mut secret_key = [0u8; SECRET_KEY_LENGTH];
secret_key.copy_from_slice(value.private_key.as_bytes());
let verifying_key = if let Some(public_key) = value.public_key {
if public_key.has_unused_bits() {
return Err(pkcs8::Error::KeyMalformed);
}
let public_key = public_key.raw_bytes();
if public_key.len() != PUBLIC_KEY_LENGTH {
return Err(pkcs8::Error::KeyMalformed);
}
let mut bytes = [0u8; PUBLIC_KEY_LENGTH];
bytes.copy_from_slice(public_key);
Some(bytes)
} else {
None
};
Ok(KeypairBytes {
secret_key,
verifying_key,
})
}
}

It checks value.private_key.as_bytes().len() != SECRET_KEY_LENGTH, but value.private_key.as_bytes() returns the whole base64 encoded data, including the PKCS8 header.

let (_, pkcs8_bytes) = pem_rfc7468::decode_vec(PRIVATE_KEY.as_bytes()).unwrap();
let info = pkcs8::PrivateKeyInfoRef::try_from(pkcs8_bytes.as_slice()).unwrap();
println!("{:02x?}", info.private_key.as_bytes());

This prints [04, 39, 8a, ec, 17, 6f, 09, 96, ff, cd, 07, 64, 82, 8d, 3c, f4, 03, 1e, 7b, f0, 34, e1, b5, c1, ac, 92, 5d, 35, 68, f1, 72, 8c, 8b, 10, cb, 1d, 0e, df, 87, 3f, b2, cb, 59, dd, 27, aa, 15, ba, 4f, eb, 68, b3, ae, 97, 12, ac, c0, d7, 24]

Letting openssl print the info about the key:

➜  openssl pkey -in ed448-key.pem -text -noout
ED448 Private-Key:
priv:
    8a:ec:17:6f:09:96:ff:cd:07:64:82:8d:3c:f4:03:
    1e:7b:f0:34:e1:b5:c1:ac:92:5d:35:68:f1:72:8c:
    8b:10:cb:1d:0e:df:87:3f:b2:cb:59:dd:27:aa:15:
    ba:4f:eb:68:b3:ae:97:12:ac:c0:d7:24

We see that it's the same data, without the first 2 bytes.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions