-
Notifications
You must be signed in to change notification settings - Fork 42
Ledger backend is not on par with tendermint votes/proposals #171
Comments
I've managed to get the same sign bytes for SignProposal if I add
sign_bytes for SignProposal with the Yubi:
sign_bytes for SignProposal with the Ledger given that all yubihsm stuff is compiled as well:
However on the above sign_bytes the ledger fails as you can see from the first log from |
However for SignVote with compiled ledger and yubihsm features the sign_bytes are wrong.
I can't explain why the conditional compilation of the |
Yes, but still.. that first byte is unexpected and out of spec. |
Oh 119 is not in the spec? |
well.. at least the spec for how votes/proposals where going to be serialized. The ledger will expect |
It seems like the ledger test-vectors are not up to date. That is easy to fix. The other problem (sign bytes seem to differ depending on if compiled with yubihsm or not) is rather mysterious tho. |
Ok, the issue is now clear :) |
I will write a fix + additional test and check other types too. |
OK, wait: In the test-vectors you've linked func (vote *Vote) SignBytes(chainID string) []byte {
bz, err := cdc.MarshalBinaryLengthPrefixed(CanonicalizeVote(chainID, vote))
if err != nil {
panic(err)
}
return bz
} which corresponds to |
ok, so should I then update the test vectors and the spec for the ledger app? |
Yes, sorry that the test vectors skip the length. I think initially they were length encoded. Must have been changed in PR (in tm). |
This is amazing. Thank you very much for looking into this. @liamsi What is the best way to investigate why the YubiHSM feature is needed for correct compilation? |
I can't reproduce why the bytes differ depending on how you compile (tried with all features available here). Can you elaborate a bit how you've compiled it? |
Cargo.toml
I added logging output to /// Perform a digital signature operation
fn sign<T: TendermintRequest + Debug>(&mut self, mut request: T) -> Result<Response, KmsError> {
debug!("got sign request");
request.validate()?;
let mut to_sign = vec![];
request.sign_bytes(self.chain_id, &mut to_sign)?;
debug!("sign_bytes for request: {:?}", to_sign);
// TODO(ismail): figure out which key to use here instead of taking the only key
// from keyring here:
let sig = KeyRing::sign(None, &to_sign)?;
request.set_signature(&sig);
debug!("successfully signed request:\n {:?}", request);
Ok(request.build_response())
} I'm logging the sign_bytes and below I'll paste the sign_bytes. Compiling with YubiHSM enabled
tmkms.toml
Truncated output from tmkms:
Compiling with Ledger enabled but without YubiHSM
tmkms.toml
Truncated output from tmkms
The reason why the Ledger doesn't return a proper signature have been discussed above and will hopefully be fixed soon. However, I don't understand why the first byte is different in the SignProposal Request is different and why the bytes for the SignVote Request are completely different. As far as I can tell nothing in the code leading up until the point of calling
is branching on whether the YubiHSM or Ledger feature is enabled.
|
Quick update:
|
Fantastic :-) I can't wait to test the entire pipeline. I also created #172 which integrates the current ledger version into it. It needs updating with your changes though or we can discard it and pull in yours. |
I am happy to take it and apply my changes on top. I will do it tomorrow morning then. |
I think this can be closed. This was fixed here: tendermint/signatory#141. And as far as I can see, the original concerns raised by Adrian (that this does depend on with which feature you compile with) do not hold. Feel free to reopen if there is still an issue. |
This seems to be a larger problem with the KMS implementation. Currently the sign_bytes that are returned in
session.rs/sign()
change depending on whether the KMS is compiled with the YubiHSM backend or the Ledger backend. This should never be the case since the KMS should be agnostic to the backend being used.So I've added logging after the sign_bytes method in called in
session.rs/sign()
. With the YubiHSM it results inProposal: 119
Prevote: 109 or 110
Precommit: 109 or 110
With the ledger it results in:
Proposal: 120
Prevote: 37
However the sign() method is called before it ever reaches any specific backend HSM. One reason for these errors could be that due to the conditional compilation with "--features" the KMS generates different data depending on which features are turned on.
@tarcieri @liamsi I have no idea why this happens. With the Yubi HSM it works fine and sign_bytes returns the correct values, whereas if you don't compile with yubihsm the returned sign_bytes are wrong.
The second issue here is that the Ledger validator application does not expect these sign_bytes, since they are divergent from the specification. The reason why this only appears with the ledger is that the YubiHSM will just sign whatever it is given, but the ledger actually decodes the bytes. @jleni
The text was updated successfully, but these errors were encountered: