From 359265a3a842698b5bdf93c6be64e3bcfee745bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=89=E4=B8=89?= Date: Fri, 16 Aug 2024 20:26:16 +0800 Subject: [PATCH] fix: send raw plaintext public key during handshake (#2599) In js, all "public keys" are marshaled using protobuf PublicKey message. However, according to [specs](https://github.com/libp2p/specs/blob/master/plaintext/README.md) and other implementations, the `Data` field should contains the raw key, instead of the protobuf marshaled key, and then put in to the exchange. Otherwise, js-libp2p will not connect to golang or rust libp2p, raising the "Public key did not match id" error. --------- Co-authored-by: Alex Potsides --- .../package.json | 3 ++- .../src/index.ts | 24 +++++++++++++++---- packages/integration-tests/package.json | 6 ++--- packages/integration-tests/test/interop.ts | 3 +++ 4 files changed, 27 insertions(+), 9 deletions(-) diff --git a/packages/connection-encrypter-plaintext/package.json b/packages/connection-encrypter-plaintext/package.json index a95043bf31..e774d50654 100644 --- a/packages/connection-encrypter-plaintext/package.json +++ b/packages/connection-encrypter-plaintext/package.json @@ -52,7 +52,9 @@ "doc-check": "aegir doc-check" }, "dependencies": { + "@libp2p/crypto": "^4.1.9", "@libp2p/interface": "^1.7.0", + "@libp2p/peer-id-factory": "^4.2.4", "@libp2p/peer-id": "^4.2.4", "it-protobuf-stream": "^1.1.3", "it-stream-types": "^2.0.1", @@ -62,7 +64,6 @@ "devDependencies": { "@libp2p/interface-compliance-tests": "^5.4.12", "@libp2p/logger": "^4.0.20", - "@libp2p/peer-id-factory": "^4.2.4", "@multiformats/multiaddr": "^12.2.3", "aegir": "^44.0.1", "protons": "^7.5.0", diff --git a/packages/connection-encrypter-plaintext/src/index.ts b/packages/connection-encrypter-plaintext/src/index.ts index af482b25c7..78a7c1d6c0 100644 --- a/packages/connection-encrypter-plaintext/src/index.ts +++ b/packages/connection-encrypter-plaintext/src/index.ts @@ -20,11 +20,13 @@ * ``` */ +import { supportedKeys } from '@libp2p/crypto/keys' import { UnexpectedPeerError, InvalidCryptoExchangeError, serviceCapabilities } from '@libp2p/interface' -import { peerIdFromBytes, peerIdFromKeys } from '@libp2p/peer-id' +import { peerIdFromBytes } from '@libp2p/peer-id' +import { createFromPubKey } from '@libp2p/peer-id-factory' import { pbStream } from 'it-protobuf-stream' -import { Exchange, KeyType } from './pb/proto.js' -import type { ComponentLogger, Logger, MultiaddrConnection, ConnectionEncrypter, SecuredConnection, PeerId } from '@libp2p/interface' +import { Exchange, KeyType, PublicKey } from './pb/proto.js' +import type { ComponentLogger, Logger, MultiaddrConnection, ConnectionEncrypter, SecuredConnection, PeerId, PublicKey as PubKey } from '@libp2p/interface' import type { Duplex } from 'it-stream-types' import type { Uint8ArrayList } from 'uint8arraylist' @@ -91,7 +93,7 @@ class Plaintext implements ConnectionEncrypter { id: localId.toBytes(), pubkey: { Type: type, - Data: localId.publicKey ?? new Uint8Array(0) + Data: localId.publicKey == null ? new Uint8Array(0) : (PublicKey.decode(localId.publicKey).Data ?? new Uint8Array(0)) } }, { signal @@ -116,7 +118,19 @@ class Plaintext implements ConnectionEncrypter { throw new Error('Remote id missing') } - peerId = await peerIdFromKeys(response.pubkey.Data) + let pubKey: PubKey + + if (response.pubkey.Type === KeyType.RSA) { + pubKey = supportedKeys.rsa.unmarshalRsaPublicKey(response.pubkey.Data) + } else if (response.pubkey.Type === KeyType.Ed25519) { + pubKey = supportedKeys.ed25519.unmarshalEd25519PublicKey(response.pubkey.Data) + } else if (response.pubkey.Type === KeyType.Secp256k1) { + pubKey = supportedKeys.secp256k1.unmarshalSecp256k1PublicKey(response.pubkey.Data) + } else { + throw new Error('Unknown public key type') + } + + peerId = await createFromPubKey(pubKey) if (!peerId.equals(peerIdFromBytes(response.id))) { throw new Error('Public key did not match id') diff --git a/packages/integration-tests/package.json b/packages/integration-tests/package.json index bddbea2579..f49fec42bb 100644 --- a/packages/integration-tests/package.json +++ b/packages/integration-tests/package.json @@ -49,7 +49,7 @@ "@libp2p/interface": "^1.3.1", "@libp2p/interface-compliance-tests": "^5.4.4", "@libp2p/interface-internal": "^1.2.1", - "@libp2p/interop": "^12.1.0", + "@libp2p/interop": "^12.2.0", "@libp2p/kad-dht": "^12.0.16", "@libp2p/logger": "^4.0.12", "@libp2p/mdns": "^10.0.23", @@ -57,7 +57,7 @@ "@libp2p/peer-id": "^4.1.1", "@libp2p/peer-id-factory": "^4.1.1", "@libp2p/ping": "^1.0.18", - "@libp2p/plaintext": "^1.0.23", + "@libp2p/plaintext": "^1.1.5", "@libp2p/tcp": "^9.0.25", "@libp2p/tls": "^1.0.10", "@libp2p/webrtc": "^4.0.32", @@ -70,7 +70,7 @@ "delay": "^6.0.0", "detect-browser": "^5.3.0", "execa": "^9.1.0", - "go-libp2p": "^1.2.0", + "go-libp2p": "^1.5.0", "it-all": "^3.0.6", "it-pipe": "^3.0.1", "libp2p": "^1.5.2", diff --git a/packages/integration-tests/test/interop.ts b/packages/integration-tests/test/interop.ts index 01f0a4a4c9..a768481179 100644 --- a/packages/integration-tests/test/interop.ts +++ b/packages/integration-tests/test/interop.ts @@ -13,6 +13,7 @@ import { kadDHT, passthroughMapper } from '@libp2p/kad-dht' import { logger } from '@libp2p/logger' import { mplex } from '@libp2p/mplex' import { peerIdFromKeys } from '@libp2p/peer-id' +import { plaintext } from '@libp2p/plaintext' import { tcp } from '@libp2p/tcp' import { tls } from '@libp2p/tls' import { multiaddr } from '@multiformats/multiaddr' @@ -160,6 +161,8 @@ async function createJsPeer (options: SpawnOptions): Promise { opts.connectionEncryption?.push(noise()) } else if (options.encryption === 'tls') { opts.connectionEncryption?.push(tls()) + } else if (options.encryption === 'plaintext') { + opts.connectionEncryption?.push(plaintext()) } if (options.muxer === 'mplex') {