Skip to content

[BUG] Peer does not block general messages before requested certificate exchange #233

@dorzepowski

Description

@dorzepowski

Bug Description

When using the Peer struct/class, it is possible to request certificates from the remote peer during the initial handshake. However, even if certificates are requested, there is currently no mechanism blocking the handling of general messages before the certificate exchange and validation are completed. This allows general message exchange to occur before authentication/authorization has been properly completed.

Related issue in TypeScript SDK: bsv-blockchain/ts-sdk#340

Steps to Reproduce

  1. Create two Peer instances,
    a. One requesting certificates from the other during handshake.
    b. Second shouldn't have any certificates to send (use listenForCertificatesRequested to prevent sending certificates)
  2. Add general message listener to record received messages,
  3. Use ToPeer to send a message,
  4. Observe that the general message is processed without any error, despite the missing certificates.

IMHO could be tested by adding following test to peer_test.go

func TestGeneralMessageRejectedBecauseCertificatesWereNotProvided(t *testing.T) {
	// given:
	alice, bob := CreateActorsPair(t)

	// and: Alice has some certificate
	aliceCertManager := testcertificates.NewManager(t, alice.Wallet, testcertificates.WithSkipAssignToSubjectWallet())

	aliceCert := aliceCertManager.CertificateForTest().WithType(contactCertTypeName).
		WithFieldValue(emailField, aliceName+"@example.com").
		Issue()

	alice.ListenForCertificatesRequested(func(senderPublicKey *ec.PublicKey, requestedCertificates utils.RequestedCertificateSet) error {
		return nil
	})

	// and: listen for a received message
	bob.ListenForGeneralMessages(func(senderPublicKey *ec.PublicKey, payload []byte) error {
		assert.Fail(t, "Bob should not receive a general message")
		return nil
	})

	// when: Bob (receiver) request certificates from counterparties
	bob.CertificatesToRequest = &utils.RequestedCertificateSet{
		Certifiers: []*ec.PublicKey{aliceCert.WalletCert.Certifier},
		CertificateTypes: utils.RequestedCertificateTypeIDAndFieldList{
			aliceCert.WalletCert.Type: []string{emailField},
		},
	}

	// and:
	err := alice.ToPeer(t.Context(), anyMessage, bob.IdentityKey, 5000)

	// then:
	require.Error(t, err, "Alice general message should be rejected because of missing certificates response: thanks to mock transport Alice should get info about rejected certificate")
}

Expected Behavior

If certificates are requested in the Peer constructor, the Peer should require that certificate exchange and validation are completed before any general message is processed. If a general message arrives before certificate validation, an error should be returned and the message should not be processed.

Actual Behavior

Currently, even when certificates are requested, the Peer processes general messages immediately after handshake, without waiting for certificate exchange or validation. This means authentication and authorization are not enforced before general message exchange.

Why Is This a Problem?

  • This is counter-intuitive and may mislead developers who expect authentication and authorization to be completed before general communication.
  • It introduces unnecessary burden, requiring each developer to independently implement certificate gating logic.
  • Centralizing certificate gating within the SDK ensures easier maintenance and bug fixes.
  • Allowing general messages before certificate validation may introduce security risks and inconsistent behavior.
  • SDKs should enforce authentication/authorization flows by default to reduce implementation errors.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    Status

    No status

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions