dotnet / dotnet/aspnetcore

DBSC registration returns 500 instead of 400 for a proof with invalid UTF-8 in the jwk

Open
#69,180 1 comment 0 reactions 1 assignee Claimed by @rokonec View on GitHub
area-auth
Dominant language
C#
Stars
38.4k
Forks
10.9k
Avg merge
2d 6h
Merged PRs (30d)
290

Description

### Is there an existing issue for this?

- [x] I have searched the existing issues

### Describe the bug

The DBSC registration endpoint (`POST /.well-known/dbsc/registration`) answers a crafted registration proof with an unhandled `System.InvalidOperationException` -- surfaced as **HTTP 500** -- where a rejected proof is meant to produce **400**.

### Expected Behavior

In such case `400 Bad request` should be returned as a result for the api call.

### Steps To Reproduce

```csharp
using Microsoft.AspNetCore.Authentication.Cookies;

var builder = WebApplication.CreateBuilder(args);
builder.Logging.ClearProviders();
builder.WebHost.UseUrls("http://127.0.0.1:5199");

builder.Services
.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie()
.AddDeviceBoundSession(CookieAuthenticationDefaults.AuthenticationScheme);

var app = builder.Build();
app.UseAuthentication();
app.MapGet("/", () => "ok");

await app.RunAsync();
```
Prepare and call the API with invalid and invalid utf-8 byte in jwt
```csharp
static string B64Url(byte[] b) => Convert.ToBase64String(b).TrimEnd('=').Replace('+', '-').Replace('/', '_');
byte[] header =
[
.. "{\"alg\":\"ES256\",\"typ\":\"dbsc+jwt\",\"jwk\":{\"kty\":\"EC\",\"crv\":\"P-256\",\"x\":\""u8,
0xA6,
.. "\"}}"u8,
];
string proof = $"{B64Url(header)}.{B64Url("{}"u8.ToArray())}.{B64Url(new byte[64])}";

using var http = new HttpClient();

async Task Post(HttpClient client, string label, string headerValue)
{
var req = new HttpRequestMessage(HttpMethod.Post, "http://127.0.0.1:5199/.well-known/dbsc/registration");
req.Headers.TryAddWithoutValidation("Secure-Session-Response", headerValue);
try
{
var resp = await client.SendAsync(req);
Console.WriteLine($"{label,-22} -> HTTP {(int)resp.StatusCode} {resp.StatusCode}");
}
catch (Exception ex)
{
Console.WriteLine($"{label,-22} -> transport failure: {ex.GetType().Name}: {ex.Message}");
}
}

await Post(http, "garbage proof", "not-a-jwt"); // 400 Bad Request
await Post(http, "malformed-utf8 jwk", proof); // 500 Internal server error
```

### Exceptions (if any)

Internally the `ValidateAsync` throws `System.InvalidOperationException: Cannot transcode invalid UTF-8 JSON text to UTF-16 string.`. Because it is not guarded with try-catch and throws, null is not returned in such case and later it's not converted to 400 Bad request by the handler.

### .NET Version

.NET 11.0.0-rc.1.26425.128

### Anything else?

Tested against Microsoft.AspNetCore.Authentication.DeviceBoundSessions 0.11.0-rc.1.26425.128.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.