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

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions