Skip to content

Add service-name check and regress test#953

Draft
yosuke-wolfssl wants to merge 1 commit intowolfSSL:masterfrom
yosuke-wolfssl:f_1274
Draft

Add service-name check and regress test#953
yosuke-wolfssl wants to merge 1 commit intowolfSSL:masterfrom
yosuke-wolfssl:f_1274

Conversation

@yosuke-wolfssl
Copy link
Copy Markdown
Contributor

This PR adds the service-name check to comply with RFC 4252 section 5.
If service name is not equal to "ssh-connection", SSH_MSG_USERAUTH_FAILURE would be sent to the peer.
Also, new unit test is added to exercise service-name validation.

@yosuke-wolfssl yosuke-wolfssl self-assigned this Apr 24, 2026
Copilot AI review requested due to automatic review settings April 24, 2026 04:46
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds RFC 4252 §5 compliance by validating the service-name in SSH_MSG_USERAUTH_REQUEST and rejecting requests that do not target "ssh-connection" while keeping the connection open for retry. It also introduces a new internal test hook and a unit test intended to exercise the new validation behavior.

Changes:

  • Add service-name validation in DoUserAuthRequest() and send SSH_MSG_USERAUTH_FAILURE when invalid.
  • Expose DoUserAuthRequest() via a new wolfSSH_TestDoUserAuthRequest() internal test wrapper.
  • Add a new unit test to exercise service-name validation logic.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
wolfssh/internal.h Adds a new internal test API declaration for invoking DoUserAuthRequest() from unit tests.
src/internal.c Implements the service-name check and the corresponding test wrapper.
tests/unit.c Adds a unit test for service-name validation and wires it into the unit test runner.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread tests/unit.c Outdated
Comment thread tests/unit.c Outdated
Comment thread src/internal.c
Comment thread src/internal.c
@padelsbach
Copy link
Copy Markdown
Contributor

@yosuke-wolfssl, can you please rebase to resolve conflicts?

Copy link
Copy Markdown

@wolfSSL-Fenrir-bot wolfSSL-Fenrir-bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fenrir Automated Review — PR #953

Scan targets checked: wolfssh-bugs, wolfssh-src

No new issues found in the changed files. ✅

Copy link
Copy Markdown
Member

@aidangarske aidangarske left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Skoll Code Review

Scan type: review
Overall recommendation: APPROVE
Findings: 7 total — 7 posted, 0 skipped
7 finding(s) posted as inline comments (see file-level comments below)

Posted findings

  • [Low] Inconsistent cast style in new NameToId callsrc/internal.c:8405-8406
  • [Low] Error from SendUserAuthFailure overwrites ret, making invalid-service path return non-successsrc/internal.c:8405-8411
  • [Low] *idx = len is written even when SendUserAuthFailure returned an errorsrc/internal.c:8409-8411
  • [Low] Test assumes output path succeeds on a fresh session without documentationtests/unit.c:952-1041
  • [Low] Test does not cover empty or oversize service namestests/unit.c:964-973
  • [Info] serviceValid could be replaced by a guard-style early return block for readabilitysrc/internal.c:8370,8417
  • [Info] *idx = len set before SendUserAuthFailure result is checkedsrc/internal.c:8409-8410

Review generated by Skoll

Comment thread src/internal.c
Comment thread src/internal.c
begin += authData.serviceNameSz;

ret = GetSize(&authData.authNameSz, buf, len, &begin);
if (NameToId((const char*)authData.serviceName, authData.serviceNameSz)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 [Low] Error from SendUserAuthFailure overwrites ret, making invalid-service path return non-success

When the service name is invalid the code calls ret = SendUserAuthFailure(ssh, 0). If SendUserAuthFailure() fails (e.g., WS_SOCKET_ERROR_E, WS_WANT_WRITE), that error is returned to the outer dispatcher as if parsing itself failed. In the unknown-auth-method path below (line 8444) the same pattern is used, so this is internally consistent with the existing convention — but it is worth confirming that propagating a send error here is the intended behavior (e.g., WS_WANT_WRITE from a non-blocking socket could reach DoReceive here and bubble up differently than the caller expects). The unit test uses a capture-callback that always returns success, so this path is not exercised.

Fix: Confirm that it is acceptable to return the SendUserAuthFailure() result (including WS_WANT_WRITE) to the DoReceive loop when the only parsing failure was a bad service name. If the intent is "we handled this request, stay alive," consider saving the send result separately from ret or adding a test where the IO callback returns WS_CBIO_ERR_WANT_WRITE.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll keep current convention as-is.
I didn't find any problematic behaviour for now.

Comment thread src/internal.c
!= ID_SERVICE_CONNECTION) {
WLOG(WS_LOG_DEBUG, "DUAR: Invalid service name");
serviceValid = 0;
ret = SendUserAuthFailure(ssh, 0);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 [Low] *idx = len is written even when SendUserAuthFailure returned an error

On the invalid-service path, ret = SendUserAuthFailure(ssh, 0); *idx = len; advances idx unconditionally. If SendUserAuthFailure returns a non-success value (e.g., a non-blocking WS_WANT_WRITE or an allocation failure inside PreparePacket), the function returns the error to DoPacket but idx is still fully consumed. For most error paths this is harmless because the caller tears the connection down, but it does mean the decoded-length cursor no longer matches what was actually processed. Other handlers in this file leave idx alone when ret is non-success.

Fix: Consider only advancing *idx = len when SendUserAuthFailure returns WS_SUCCESS, matching the idx-preservation convention used elsewhere in this function on error paths.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This shall consume all of data to release the input buffer properly.
I fixed both of cases.

Comment thread tests/unit.c
Comment thread tests/unit.c
Comment thread src/internal.c
Comment thread src/internal.c
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants