-
Notifications
You must be signed in to change notification settings - Fork 8.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add ed25519 support #3343
Add ed25519 support #3343
Conversation
I generally support this idea, and am in favor of it, but unfortunately adding support for ed25519 in a safe manner is more complex than just adding the code for generating signatures and verifying them. If you could atomically and instantly upgrade all nodes of a Fabric network to support ed25519 then there wouldn't have been any problem at all. But Fabric nodes may be upgraded at different times, and some nodes might be offline or unreachable and then afterwards be reachable and online again and these nodes will receive the ed25519 signatures and they will reject them. The key problem is that we need a way for Fabric validation to understand that "until a certain point in the blockchain, all ed25519 signatures are invalid" and "starting from a certain point in the blockchain, all ed25519 signatures are valid". In Fabric, this is done using the capabilities feature. Essentially, you "mark" in the channel config a certain configuration property and then the nodes know when to use that property and when not to use it. |
Aside from my comment above, the PR is missing integration tests that generate ed25519 crypto material, and run a network and transact to ensure everything is good. |
@@ -110,10 +112,10 @@ func testGenerateLocalMSP(t *testing.T, nodeOUs bool) { | |||
} | |||
|
|||
tlsCA.Name = "test/fail" | |||
err = msp.GenerateLocalMSP(testDir, testName, nil, signCA, tlsCA, msp.CLIENT, nodeOUs) | |||
err = msp.GenerateLocalMSP(testDir, testName, nil, signCA, tlsCA, msp.CLIENT, nodeOUs, ECDSA) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see that you didn't changed the MSP (top level msp package
).
The MSP needs to be versioned like here from the aforementioned reasons.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for all your comments! I intend to add more work to it during the following weeks.
Incidentally, have you checked that the verification takes care of https://datatracker.ietf.org/doc/html/rfc8032#section-8.4 We had to do this manually for ecdsa |
It seems that golang has already implemented it: In previous versions they even had a comment about preventing signature malleability: https://github.com/golang/go/blob/go1.15/src/crypto/ed25519/ed25519.go#L235 |
@johannww On ed25519 support for node fabric-gateway... I'm sure you already know the signing implementation is entirely pluggable. The client application can supply its own (ed25519) signing implementation and the API doesn't need to have an implementation built in. However, I would be quite happy to include this in the API. Just note that there need to be implementations in all three client languages (Go, Type/JavaScript and Java). |
f0ec525
to
84c4ea8
Compare
msp/mspimplsetup.go
Outdated
@@ -656,6 +659,22 @@ func (msp *bccspmsp) setupV142(conf *m.FabricMSPConfig) error { | |||
return nil | |||
} | |||
|
|||
func (msp *bccspmsp) setupV24(conf *m.FabricMSPConfig) error { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Lets put setupV3
integration/nwo/standard_networks.go
Outdated
@@ -181,6 +181,30 @@ func MultiChannelBasicSolo() *Config { | |||
return config | |||
} | |||
|
|||
func Ed25519Solo() *Config { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why do you need a config for ED25519 ? There is nothing unique about this config that is related to ed25519. In the integration test you can just take an existing config, no?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I probably don't. I only created there as a temporary solution. Peers can be added externally to this configuration function anyway.
integration/nwo/network.go
Outdated
@@ -1439,6 +1461,79 @@ func (n *Network) peerCommand(command Command, tlsDir string, env ...string) *ex | |||
return cmd | |||
} | |||
|
|||
func (n *Network) downloadOldBinaries(fabricVersion string) error { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why do you need this downloadOldBinaries
?
integration/nwo/network.go
Outdated
return nil | ||
} | ||
|
||
func (n *Network) oldPeerCommand(command Command, fabricVersion string, tlsDir string, env ...string) *exec.Cmd { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why do you need to have this oldPeerCommand
command?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the integration test integration/lifecycle/capabilities_endorse_test.go I upgrade the channel capabilities and intend to show that a peer that does not have source code to support it won't endorse any more transactions. Therefore, one of the peers runs with a fabric v2.4.5 binary, downloaded from Github.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
did you mean to say "does not" instead of "does" ? I still don't understand, why would the peer not endorse transactions? If you enable a capability and a peer cannot support it, it simply crashes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I assumed that the peer crash should be proven. If you consider this verification unnecessary I can remove it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes please remove
integration/ed25519/config_test.go
Outdated
@@ -0,0 +1,1859 @@ | |||
/* | |||
Copyright IBM Corp All Rights Reserved. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think a single integration test that:
- Has peers and orderers in it
- Transacts on a channel
- The channel contains both ECDSA and ed25519 identities and they're both used in the endorsement policy
Is sufficient.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That is my intention. This commit was not meant as a final solution yet but a work in progress. The folder integration/ed25519 will be removed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
By "peers and odererS" do you mean I should use a raft configuration with at least two orderers?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Knowing the Raft code, you don't have to use several Raft nodes to test ed25519. One is sufficient. But you can use three, I think it's easier from a copy-paste aspect that to use one.
integration/ed25519/client.go
Outdated
return blk | ||
} | ||
|
||
func CreateBroadcastEnvelope(n *nwo.Network, entity interface{}, channel string, data []byte) *common.Envelope { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we have these functions already in the code, I don't think we need to add them again in another place. Let's just use the functions that exist
Ok i understand this is still work in progress. So please tag me once you feel this is ready. |
cmd/common/signer/signer.go
Outdated
case *ecdsa.PrivateKey: | ||
return signECDSA(si.key.(*ecdsa.PrivateKey), digest) | ||
case ed25519.PrivateKey: | ||
return ed25519.Sign(si.key.(ed25519.PrivateKey), digest), nil |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this correct? The godoc suggests that, while ecdsa sign takes a hash/digest, the ed25519 sign requires the entire message bytes. There is more detail in the PrivateKey Sign method doc:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
based on the tests of the ed25519 package, you need to pass a message and not a hash.
And this means that the verifier needs to be changed accordingly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am evaluating a possible solution, as I believe these requirements will lead to changes in the Signer interface
So functions like the one below can be called:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it is fixed. Plus, I forced-pushed some commits because they were not signed off.
7f2ffdf
to
889907a
Compare
gossip/discovery/discovery_impl.go
Outdated
for i := range deadMembers2Expire { | ||
d.logger.Warning("Closing connection to", deadMembers2Expire[i]) | ||
d.comm.CloseConn(&deadMembers2Expire[i]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see the benefit of changing the code to look up the value twice by index instead of just directly using the value provided by for-range, as the code did before
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see how this is related to the pull request's intention.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do not consider that. This is the result of a forced push that I have done to sign my commits. I accidentally signed commits that were not mine. I will fix that and probably force-push again.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no worries
@@ -0,0 +1,261 @@ | |||
/* |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any specific handling for ed25519 that influences lifecycle specifically?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No. I just put it in the lifecycle folder because it seemed the most related integration test "family", considering your previous #suggestions:
I think a single integration test that:
- Has peers and orderers in it
- Transacts on a channel
- The channel contains both ECDSA and ed25519 identities and they're both used in the endorsement policy
Is sufficient.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i see, ok
a007b56
to
272fa3e
Compare
Warning1: This branch must be run with the fabric pull-request branch on hyperledger/fabric#3343 Warning2: The java gateway does not support ed25519 TLS certificates. This will lead to either warning users that java-gateway cannot communicate to ed25519 peers/orderers with TLS certificates OR the pull request on hyperledger/fabric#3343 fabric should disable ed25519 TLS certificates. Signed-off-by: Johann Westphall <[email protected]>
One important issue: I am implementing Ed25519 support for fabric-gateway using the code in this pull request as my Hyperledger Fabric. I created the crypto-material by setting field PublicKeyAlgorithm to ed25519, instead of ecdsa as here: This generated ed25519 TLS keys for the peers. When running the scenario-test, only the java-gateway failed in a scenario with ed25519 TLS keys, due to the library netty (see the issue). I see 2 possible ways to go from here, regarding changes to fabric and/or gateway:
|
I noticed this JDK issue, which says TLS support for EdDSA signatures was added in Java 16: https://bugs.openjdk.org/browse/JDK-8254709 Any chance that it worked with Java 17?
I think I would be happy to proceed with only Java clients not currently able to establish TLS connections to peers that use Ed25519 keys. There is precedent for certain crypto only being supported by certain client, such as Idemix. This is clearly a bug outside of our control and should get fixed at some point. |
Fabric's TLS stack is generally up to the Go standard library, so if you use a Java client willingly, it is up to you to be able to connect correctly to the TLS stack of the nodes. Generally, as a rule of thumb - Fabric core sets the standard, and the clients track the Fabric core, and not the other way around. |
Considering the efforts to give ed25519 support in fabric and fabric-gateway, this commit intends to provide ed25519 support for fabric-ca. With these efforts, cryptogen can generate ed25519 keys for the CA, motivating these changes to keep compatibility in terms of crypto support. Fabric main branch current version (3.0.0) does not support RSA anymore. For that reason, I had to manually merge the ed25519 pull request (hyperledger/fabric#3343) with fabric v1.4.11. The adapated version replaces fabric v1.4.11 in 'go.mod'. Signed-off-by: Johann Westphall <[email protected]>
Signed-off-by: Johann Westphall <[email protected]>
Signed-off-by: Johann Westphall <[email protected]>
Signed-off-by: Johann Westphall <[email protected]>
- instead of changing cryptogen config, we give ed25519 keys by changing the certificate and the keys. - Now, the test is compatible with a network without a system channel. - Other improvements were made Signed-off-by: Johann Westphall <[email protected]>
Signed-off-by: Johann Westphall <[email protected]>
Signed-off-by: Johann Westphall <[email protected]>
Signed-off-by: Johann Westphall <[email protected]>
Signed-off-by: Johann Westphall <[email protected]>
Signed-off-by: Johann Westphall <[email protected]>
@yacovm @denyeart @adecaro @ale-linux this PR is now building successfully against the BCCSP updates delivered in hyperledger/fabric-lib-go#29. Can you re-review? |
integration/nwo/cryptogen_config.go
Outdated
Users UsersSpec `yaml:"Users"` | ||
} | ||
|
||
type CryptogenConfig struct { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
where is this used?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On previous tests, I used cryptogen to give ed25519 credentials. It has no use now. It will be removed.
Value: protoutil.MarshalOrPanic( | ||
&common.Capabilities{ | ||
Capabilities: map[string]*common.Capability{ | ||
capabilitiesVersion: {}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm confused, where do you enable the V3_0 capability here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I followed the example of ./integration/e2e/e2e_test.go#L197-L198, which is a pattern repeated in many integration tests. V3_0 capabilities are enabled by line 518.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh I see, the capabilitiesVersion you pass is set to V3_0
}) | ||
|
||
It("invoke chaincode after upgrading Channel to V3_0 and add ed25519 peer and orderer", func() { | ||
networkConfig := nwo.MultiNodeEtcdRaft() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So we have a single organization with 2 orderers of ECDSA and 1 orderer that is offline, and later is brought online to be ed25519 ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Almost that. Initially, we have 3 ECDSA orderers from a single organization. Later, orderer3 is killed, given an ed25519 key, and restarted. In contrast, there are 2 ECDSA peers from different orgs and an ed25519 offline one. The ed25519 peer is only started once, directly with ed25519 keys.
// sign the DIGEST | ||
// The same applies to the Verify function | ||
func TestSignatureAlgorithms(t *testing.T) { | ||
gt := gomega.NewGomegaWithT(t) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not that it matters, but, any reason you use gomega here and not "github.com/stretchr/testify/require" ?
The entire package is using the latter
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did not notice and was probably inspired by a gomega test file. I can change that to keep coherence.
@johannww I just wanted to say thank you for sticking with this pull request. I acknowledge that it has taken a very long time to fully review it, but this is indeed on our list for the upcoming v3.0 release. Do you have any interest in adding ed25519 support to fabric-ca for certificate issuance? |
Signed-off-by: Johann Westphall <[email protected]>
Signed-off-by: Johann Westphall <[email protected]>
@denyeart You're welcome. I remember. I tried to add ed25519 to the fabric-ca previously but stumbled into a problem with cloudfare cfssl support for ed25519: cloudflare/cfssl#1097 (comment). Here is my old fork of fabric-ca: https://github.com/johannww/fabric-ca This seems to be solved and merged. I should take a look into it. |
ok it looks good to me, let's have @ale-linux or @adecaro also review it. |
Considering the efforts to give ed25519 support in fabric and fabric-gateway, this commit intends to provide ed25519 support for fabric-ca. With these efforts, cryptogen can generate ed25519 keys for the CA, motivating these changes to keep compatibility in terms of crypto support. Fabric main branch current version (3.0.0) does not support RSA anymore. For that reason, I had to manually merge the ed25519 pull request (hyperledger/fabric#3343) with fabric v1.4.11. The adapated version replaces fabric v1.4.11 in 'go.mod'. Signed-off-by: Johann Westphall <[email protected]>
Considering the efforts to give ed25519 support in fabric and fabric-gateway, this commit intends to provide ed25519 support for fabric-ca. With these efforts, cryptogen can generate ed25519 keys for the CA, motivating these changes to keep compatibility in terms of crypto support. Fabric main branch current version (3.0.0) does not support RSA anymore. For that reason, I had to manually merge the ed25519 pull request (hyperledger/fabric#3343) with fabric v1.4.11. The adapated version replaces fabric v1.4.11 in 'go.mod'. Signed-off-by: Johann Westphall <[email protected]>
How long do we wait for a review before merging? |
I talked to @adecaro the other day and he confirmed he will take a look so that we can get this in for v3.0... I do think it is valuable to have one of the original MSP authors take a look. |
LGTM 👍 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@johannww Thanks again for the contribution and apologies for the delays, this is now ready for merge for inclusion in Fabric v3.0!
@denyeart you're welcome! Thank you also for reviewing big pull request. @bestbeforetoday thank you for ensuring that this pull request remained active throughout this period. @yacovm thank you for all the reviews and hints given. |
Type of change
Description
Due to some considering NIST curves insecure and
Golang having ed25519 native support, there was
not a reason for not implementing in Fabric.
Tests cases for ed25519 were also added. Since
ed25519 key derivation is not called by any
function, I left as a TODO.
As I am working on ed25519 support for node fabric-gateway,
I needed to add ed25519 support for cryptogen also,
aiming to pass tests with certificates containing
ed25519 keys. Since the node fabric-gateway tests
generate their crypto material with cryptogen, I
adapted cryptogen to support ed25519 keys.
Additional details
Some tests concerning ed25519 key generation and certificate parsing
were added.
Related issues