Skip to content

Commit

Permalink
fix: parse ed25519 keys using the old strategy as a fallback
Browse files Browse the repository at this point in the history
  • Loading branch information
QuinnWilton committed Mar 12, 2024
1 parent 973245e commit b5a9167
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 12 deletions.
3 changes: 3 additions & 0 deletions homestar-runtime/fixtures/__testkey_ed25519_6.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
-----BEGIN PRIVATE KEY-----
MC4CAQAwBQYDK2VwBCIEIP/Tyqg9taY+9+pkA8EzBfsUAT6Hi+eOVuHzo1qhH5uB
-----END PRIVATE KEY-----
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[node]

[node.network.keypair_config]
# path is relative to execution
# generate a new key with openssl `openssl genpkey -algorithm ed25519 > ed25519_key.pem`
# homestar supports ed25519 and secp256k1 keys
existing = { key_type = "ed25519", path = "./fixtures/__testkey_ed25519_6.pem" }
31 changes: 30 additions & 1 deletion homestar-runtime/src/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -447,14 +447,43 @@ mod test {

#[test]
fn import_existing_key() {
// Test using a key not containing curve parameters
let settings = Settings::build(Some("fixtures/settings-import-ed25519.toml".into()))
.expect("setting file in test fixtures");

let msg = b"foo bar";
let signature = libp2p::identity::Keypair::ed25519_from_bytes([0; 32])
let key = [0; 32];
let signature = libp2p::identity::Keypair::ed25519_from_bytes(key)
.unwrap()
.sign(msg)
.unwrap();

// round-about way of testing since there is no Eq derive for keypairs
assert!(settings
.node
.network
.keypair_config
.keypair()
.expect("import ed25519 key")
.public()
.verify(msg, &signature));

// Test using a key containing curve parameters
let settings = Settings::build(Some(
"fixtures/settings-import-ed25519-with-params.toml".into(),
))
.expect("setting file in test fixtures");

let msg = b"foo bar";
let key = [
255, 211, 202, 168, 61, 181, 166, 62, 247, 234, 100, 3, 193, 51, 5, 251, 20, 1, 62,
135, 139, 231, 142, 86, 225, 243, 163, 90, 161, 31, 155, 129,
];
let signature = libp2p::identity::Keypair::ed25519_from_bytes(key)
.unwrap()
.sign(msg)
.unwrap();

// round-about way of testing since there is no Eq derive for keypairs
assert!(settings
.node
Expand Down
36 changes: 25 additions & 11 deletions homestar-runtime/src/settings/pubkey_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ impl PubkeyConfig {
}
PubkeyConfig::Existing(ExistingKeyPath { key_type, path }) => {
let path = Path::new(&path);

let mut file = std::fs::File::open(path).context("unable to read key file")?;

let mut buf = Vec::new();
Expand All @@ -144,17 +145,30 @@ impl PubkeyConfig {
path.display()
);

let mut key = ed25519_dalek::SigningKey::from_pkcs8_pem(
&String::from_utf8(buf).with_context(|| {
"unable to read PEM, file contained invalid UTF-8 code points"
})?,
)
.with_context(|| "unable to deserialize ed25119 key from PEM")?
.to_bytes();

// raw bytes of ed25519 secret key from PEM file
identity::Keypair::ed25519_from_bytes(&mut key)
.with_context(|| "imported key material was invalid for ed25519")
String::from_utf8(buf.clone()).with_context(|| {
"unable to read PEM, file contained invalid UTF-8 code points"
})
.and_then(|pem| ed25519_dalek::SigningKey::from_pkcs8_pem(&pem).with_context(|| "unable to deserialize ed25119 key from PEM"))
.and_then(|pem| {
let mut key = pem.to_bytes();

identity::Keypair::ed25519_from_bytes(&mut key).with_context(|| "imported key material was invalid for ed25519")
})
.or_else(|_| {
// parsing using ed25519_dalek failed, so try falling back to the older parsing strategy that attempts
// to deserialize the key material as a single byte vec, with no parameters included
const PEM_HEADER: &str = "PRIVATE KEY";

// to parse keys as a vec of the key material, with no parameters included
let (tag, mut key) = sec1::der::pem::decode_vec(&buf)
.map_err(|e| anyhow!("key file must be PEM formatted: {:#?}", e))?;
if tag != PEM_HEADER {
return Err(anyhow!("imported key file had a header of '{tag}', expected '{PEM_HEADER}' for ed25519"));
}

identity::Keypair::ed25519_from_bytes(&mut key)
.with_context(|| "imported key material was invalid for ed25519")
})
}
KeyType::Secp256k1 => {
info!(
Expand Down

0 comments on commit b5a9167

Please sign in to comment.